Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / instance_unittest.py @ 3d835d1b

History | View | Annotate | Download (79.1 kB)

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

24 66222813 Thomas Thrainer
"""
25 66222813 Thomas Thrainer
26 66222813 Thomas Thrainer
import copy
27 66222813 Thomas Thrainer
import itertools
28 66222813 Thomas Thrainer
import unittest
29 66222813 Thomas Thrainer
import mock
30 66222813 Thomas Thrainer
import operator
31 66222813 Thomas Thrainer
32 66222813 Thomas Thrainer
from ganeti import compat
33 66222813 Thomas Thrainer
from ganeti import constants
34 66222813 Thomas Thrainer
from ganeti import errors
35 66222813 Thomas Thrainer
from ganeti import ht
36 66222813 Thomas Thrainer
from ganeti import opcodes
37 66222813 Thomas Thrainer
from ganeti import objects
38 66222813 Thomas Thrainer
from ganeti import rpc
39 66222813 Thomas Thrainer
from ganeti import utils
40 66222813 Thomas Thrainer
from ganeti.cmdlib import instance
41 66222813 Thomas Thrainer
42 66222813 Thomas Thrainer
from cmdlib.cmdlib_unittest import _StubComputeIPolicySpecViolation, _FakeLU
43 66222813 Thomas Thrainer
44 66222813 Thomas Thrainer
from testsupport import *
45 66222813 Thomas Thrainer
46 66222813 Thomas Thrainer
import testutils
47 66222813 Thomas Thrainer
48 66222813 Thomas Thrainer
49 66222813 Thomas Thrainer
class TestComputeIPolicyInstanceSpecViolation(unittest.TestCase):
50 66222813 Thomas Thrainer
  def test(self):
51 66222813 Thomas Thrainer
    ispec = {
52 66222813 Thomas Thrainer
      constants.ISPEC_MEM_SIZE: 2048,
53 66222813 Thomas Thrainer
      constants.ISPEC_CPU_COUNT: 2,
54 66222813 Thomas Thrainer
      constants.ISPEC_DISK_COUNT: 1,
55 66222813 Thomas Thrainer
      constants.ISPEC_DISK_SIZE: [512],
56 66222813 Thomas Thrainer
      constants.ISPEC_NIC_COUNT: 0,
57 66222813 Thomas Thrainer
      constants.ISPEC_SPINDLE_USE: 1,
58 66222813 Thomas Thrainer
      }
59 66222813 Thomas Thrainer
    stub = _StubComputeIPolicySpecViolation(2048, 2, 1, 0, [512], 1,
60 66222813 Thomas Thrainer
                                            constants.DT_PLAIN)
61 66222813 Thomas Thrainer
    ret = instance._ComputeIPolicyInstanceSpecViolation(NotImplemented, ispec,
62 66222813 Thomas Thrainer
                                                        constants.DT_PLAIN,
63 66222813 Thomas Thrainer
                                                        _compute_fn=stub)
64 66222813 Thomas Thrainer
    self.assertEqual(ret, [])
65 66222813 Thomas Thrainer
66 66222813 Thomas Thrainer
67 66222813 Thomas Thrainer
class TestLUInstanceCreate(CmdlibTestCase):
68 66222813 Thomas Thrainer
  def setUp(self):
69 66222813 Thomas Thrainer
    super(TestLUInstanceCreate, self).setUp()
70 66222813 Thomas Thrainer
71 66222813 Thomas Thrainer
    self.net = self.cfg.AddNewNetwork()
72 66222813 Thomas Thrainer
    self.cfg.ConnectNetworkToGroup(self.net, self.group)
73 66222813 Thomas Thrainer
74 66222813 Thomas Thrainer
    self.node1 = self.cfg.AddNewNode()
75 66222813 Thomas Thrainer
    self.node2 = self.cfg.AddNewNode()
76 66222813 Thomas Thrainer
77 66222813 Thomas Thrainer
    self.rpc.call_os_get.side_effect = \
78 66222813 Thomas Thrainer
      lambda node, _: self.RpcResultsBuilder() \
79 66222813 Thomas Thrainer
                        .CreateSuccessfulNodeResult(node, self.os)
80 66222813 Thomas Thrainer
81 66222813 Thomas Thrainer
    hv_info = ("bootid",
82 66222813 Thomas Thrainer
               [{
83 66222813 Thomas Thrainer
                 "type": constants.ST_LVM_VG,
84 66222813 Thomas Thrainer
                 "storage_free": 10000
85 66222813 Thomas Thrainer
               }],
86 66222813 Thomas Thrainer
               ({"memory_free": 10000}, ))
87 66222813 Thomas Thrainer
    self.rpc.call_node_info.return_value = \
88 66222813 Thomas Thrainer
      self.RpcResultsBuilder() \
89 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.master, hv_info) \
90 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.node1, hv_info) \
91 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.node2, hv_info) \
92 66222813 Thomas Thrainer
        .Build()
93 66222813 Thomas Thrainer
94 66222813 Thomas Thrainer
    self.rpc.call_blockdev_getmirrorstatus.side_effect = \
95 66222813 Thomas Thrainer
      lambda node, _: self.RpcResultsBuilder() \
96 66222813 Thomas Thrainer
                        .CreateSuccessfulNodeResult(node, [])
97 66222813 Thomas Thrainer
98 66222813 Thomas Thrainer
    self.iallocator_cls.return_value.result = [self.node1.name, self.node2.name]
99 66222813 Thomas Thrainer
100 66222813 Thomas Thrainer
    self.diskless_op = opcodes.OpInstanceCreate(
101 66222813 Thomas Thrainer
      instance_name="diskless.test.com",
102 66222813 Thomas Thrainer
      pnode=self.master.name,
103 66222813 Thomas Thrainer
      disk_template=constants.DT_DISKLESS,
104 66222813 Thomas Thrainer
      mode=constants.INSTANCE_CREATE,
105 66222813 Thomas Thrainer
      nics=[{}],
106 66222813 Thomas Thrainer
      disks=[],
107 66222813 Thomas Thrainer
      os_type=self.os_name_variant)
108 66222813 Thomas Thrainer
109 66222813 Thomas Thrainer
    self.plain_op = opcodes.OpInstanceCreate(
110 66222813 Thomas Thrainer
      instance_name="plain.test.com",
111 66222813 Thomas Thrainer
      pnode=self.master.name,
112 66222813 Thomas Thrainer
      disk_template=constants.DT_PLAIN,
113 66222813 Thomas Thrainer
      mode=constants.INSTANCE_CREATE,
114 66222813 Thomas Thrainer
      nics=[{}],
115 66222813 Thomas Thrainer
      disks=[{
116 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 1024
117 66222813 Thomas Thrainer
      }],
118 66222813 Thomas Thrainer
      os_type=self.os_name_variant)
119 66222813 Thomas Thrainer
120 66222813 Thomas Thrainer
    self.block_op = opcodes.OpInstanceCreate(
121 66222813 Thomas Thrainer
      instance_name="block.test.com",
122 66222813 Thomas Thrainer
      pnode=self.master.name,
123 66222813 Thomas Thrainer
      disk_template=constants.DT_BLOCK,
124 66222813 Thomas Thrainer
      mode=constants.INSTANCE_CREATE,
125 66222813 Thomas Thrainer
      nics=[{}],
126 66222813 Thomas Thrainer
      disks=[{
127 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 1024,
128 66222813 Thomas Thrainer
        constants.IDISK_ADOPT: "/dev/disk/block0"
129 66222813 Thomas Thrainer
      }],
130 66222813 Thomas Thrainer
      os_type=self.os_name_variant)
131 66222813 Thomas Thrainer
132 66222813 Thomas Thrainer
    self.drbd_op = opcodes.OpInstanceCreate(
133 66222813 Thomas Thrainer
      instance_name="drbd.test.com",
134 66222813 Thomas Thrainer
      pnode=self.node1.name,
135 66222813 Thomas Thrainer
      snode=self.node2.name,
136 66222813 Thomas Thrainer
      disk_template=constants.DT_DRBD8,
137 66222813 Thomas Thrainer
      mode=constants.INSTANCE_CREATE,
138 66222813 Thomas Thrainer
      nics=[{}],
139 66222813 Thomas Thrainer
      disks=[{
140 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 1024
141 66222813 Thomas Thrainer
      }],
142 66222813 Thomas Thrainer
      os_type=self.os_name_variant)
143 66222813 Thomas Thrainer
144 66222813 Thomas Thrainer
    self.file_op = opcodes.OpInstanceCreate(
145 66222813 Thomas Thrainer
      instance_name="file.test.com",
146 66222813 Thomas Thrainer
      pnode=self.node1.name,
147 66222813 Thomas Thrainer
      disk_template=constants.DT_FILE,
148 66222813 Thomas Thrainer
      mode=constants.INSTANCE_CREATE,
149 66222813 Thomas Thrainer
      nics=[{}],
150 66222813 Thomas Thrainer
      disks=[{
151 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 1024
152 66222813 Thomas Thrainer
      }],
153 66222813 Thomas Thrainer
      os_type=self.os_name_variant)
154 66222813 Thomas Thrainer
155 66222813 Thomas Thrainer
  def testSimpleCreate(self):
156 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op)
157 66222813 Thomas Thrainer
    self.ExecOpCode(op)
158 66222813 Thomas Thrainer
159 66222813 Thomas Thrainer
  def testStrangeHostnameResolve(self):
160 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op)
161 66222813 Thomas Thrainer
    self.netutils_mod.GetHostname.return_value = \
162 11414807 Klaus Aehlig
      HostnameMock("random.host.example.com", "203.0.113.1")
163 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
164 66222813 Thomas Thrainer
      op, "Resolved hostname .* does not look the same as given hostname")
165 66222813 Thomas Thrainer
166 66222813 Thomas Thrainer
  def testOpportunisticLockingNoIAllocator(self):
167 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
168 66222813 Thomas Thrainer
                         opportunistic_locking=True,
169 66222813 Thomas Thrainer
                         iallocator=None)
170 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
171 66222813 Thomas Thrainer
      op, "Opportunistic locking is only available in combination with an"
172 66222813 Thomas Thrainer
          " instance allocator")
173 66222813 Thomas Thrainer
174 66222813 Thomas Thrainer
  def testNicWithNetAndMode(self):
175 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
176 66222813 Thomas Thrainer
                         nics=[{
177 66222813 Thomas Thrainer
                           constants.INIC_NETWORK: self.net.name,
178 66222813 Thomas Thrainer
                           constants.INIC_MODE: constants.NIC_MODE_BRIDGED
179 66222813 Thomas Thrainer
                         }])
180 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
181 66222813 Thomas Thrainer
      op, "If network is given, no mode or link is allowed to be passed")
182 66222813 Thomas Thrainer
183 66222813 Thomas Thrainer
  def testVlanWithWrongMode(self):
184 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
185 66222813 Thomas Thrainer
                         nics=[{
186 66222813 Thomas Thrainer
                           constants.INIC_VLAN: ":1",
187 66222813 Thomas Thrainer
                           constants.INIC_MODE: constants.NIC_MODE_BRIDGED
188 66222813 Thomas Thrainer
                         }])
189 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
190 66222813 Thomas Thrainer
      op, "VLAN is given, but network mode is not openvswitch")
191 66222813 Thomas Thrainer
192 66222813 Thomas Thrainer
  def testAutoIpNoNameCheck(self):
193 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
194 66222813 Thomas Thrainer
                         nics=[{
195 66222813 Thomas Thrainer
                           constants.INIC_IP: constants.VALUE_AUTO
196 66222813 Thomas Thrainer
                         }],
197 66222813 Thomas Thrainer
                         ip_check=False,
198 66222813 Thomas Thrainer
                         name_check=False)
199 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
200 66222813 Thomas Thrainer
      op, "IP address set to auto but name checks have been skipped")
201 66222813 Thomas Thrainer
202 66222813 Thomas Thrainer
  def testAutoIp(self):
203 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
204 66222813 Thomas Thrainer
                         nics=[{
205 66222813 Thomas Thrainer
                           constants.INIC_IP: constants.VALUE_AUTO
206 66222813 Thomas Thrainer
                         }])
207 66222813 Thomas Thrainer
    self.ExecOpCode(op)
208 66222813 Thomas Thrainer
209 66222813 Thomas Thrainer
  def testPoolIpNoNetwork(self):
210 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
211 66222813 Thomas Thrainer
                         nics=[{
212 66222813 Thomas Thrainer
                           constants.INIC_IP: constants.NIC_IP_POOL
213 66222813 Thomas Thrainer
                         }])
214 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
215 66222813 Thomas Thrainer
      op, "if ip=pool, parameter network must be passed too")
216 66222813 Thomas Thrainer
217 66222813 Thomas Thrainer
  def testValidIp(self):
218 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
219 66222813 Thomas Thrainer
                         nics=[{
220 11414807 Klaus Aehlig
                           constants.INIC_IP: "203.0.113.1"
221 66222813 Thomas Thrainer
                         }])
222 66222813 Thomas Thrainer
    self.ExecOpCode(op)
223 66222813 Thomas Thrainer
224 66222813 Thomas Thrainer
  def testRoutedNoIp(self):
225 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
226 66222813 Thomas Thrainer
                         nics=[{
227 66222813 Thomas Thrainer
                           constants.INIC_MODE: constants.NIC_MODE_ROUTED
228 66222813 Thomas Thrainer
                         }])
229 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
230 66222813 Thomas Thrainer
      op, "Routed nic mode requires an ip address")
231 66222813 Thomas Thrainer
232 66222813 Thomas Thrainer
  def testValicMac(self):
233 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
234 66222813 Thomas Thrainer
                         nics=[{
235 66222813 Thomas Thrainer
                           constants.INIC_MAC: "f0:df:f4:a3:d1:cf"
236 66222813 Thomas Thrainer
                         }])
237 66222813 Thomas Thrainer
    self.ExecOpCode(op)
238 66222813 Thomas Thrainer
239 66222813 Thomas Thrainer
  def testValidNicParams(self):
240 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
241 66222813 Thomas Thrainer
                         nics=[{
242 66222813 Thomas Thrainer
                           constants.INIC_MODE: constants.NIC_MODE_BRIDGED,
243 66222813 Thomas Thrainer
                           constants.INIC_LINK: "br_mock"
244 66222813 Thomas Thrainer
                         }])
245 66222813 Thomas Thrainer
    self.ExecOpCode(op)
246 66222813 Thomas Thrainer
247 66222813 Thomas Thrainer
  def testValidNicParamsOpenVSwitch(self):
248 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
249 66222813 Thomas Thrainer
                         nics=[{
250 66222813 Thomas Thrainer
                           constants.INIC_MODE: constants.NIC_MODE_OVS,
251 66222813 Thomas Thrainer
                           constants.INIC_VLAN: "1"
252 66222813 Thomas Thrainer
                         }])
253 66222813 Thomas Thrainer
    self.ExecOpCode(op)
254 66222813 Thomas Thrainer
255 66222813 Thomas Thrainer
  def testNicNoneName(self):
256 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
257 66222813 Thomas Thrainer
                         nics=[{
258 66222813 Thomas Thrainer
                           constants.INIC_NAME: constants.VALUE_NONE
259 66222813 Thomas Thrainer
                         }])
260 66222813 Thomas Thrainer
    self.ExecOpCode(op)
261 66222813 Thomas Thrainer
262 66222813 Thomas Thrainer
  def testConflictingIP(self):
263 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
264 66222813 Thomas Thrainer
                         nics=[{
265 66222813 Thomas Thrainer
                           constants.INIC_IP: self.net.gateway[:-1] + "2"
266 66222813 Thomas Thrainer
                         }])
267 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
268 66222813 Thomas Thrainer
      op, "The requested IP address .* belongs to network .*, but the target"
269 66222813 Thomas Thrainer
          " NIC does not.")
270 66222813 Thomas Thrainer
271 66222813 Thomas Thrainer
  def testVLanFormat(self):
272 66222813 Thomas Thrainer
    for vlan in [".pinky", ":bunny", ":1:pinky", "bunny"]:
273 66222813 Thomas Thrainer
      self.ResetMocks()
274 66222813 Thomas Thrainer
      op = self.CopyOpCode(self.diskless_op,
275 66222813 Thomas Thrainer
                           nics=[{
276 66222813 Thomas Thrainer
                             constants.INIC_VLAN: vlan
277 66222813 Thomas Thrainer
                           }])
278 66222813 Thomas Thrainer
      self.ExecOpCodeExpectOpPrereqError(
279 66222813 Thomas Thrainer
        op, "Specified VLAN parameter is invalid")
280 66222813 Thomas Thrainer
281 66222813 Thomas Thrainer
  def testPoolIp(self):
282 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
283 66222813 Thomas Thrainer
                         nics=[{
284 66222813 Thomas Thrainer
                           constants.INIC_IP: constants.NIC_IP_POOL,
285 66222813 Thomas Thrainer
                           constants.INIC_NETWORK: self.net.name
286 66222813 Thomas Thrainer
                         }])
287 66222813 Thomas Thrainer
    self.ExecOpCode(op)
288 66222813 Thomas Thrainer
289 66222813 Thomas Thrainer
  def testPoolIpUnconnectedNetwork(self):
290 66222813 Thomas Thrainer
    net = self.cfg.AddNewNetwork()
291 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
292 66222813 Thomas Thrainer
                         nics=[{
293 66222813 Thomas Thrainer
                           constants.INIC_IP: constants.NIC_IP_POOL,
294 66222813 Thomas Thrainer
                           constants.INIC_NETWORK: net.name
295 66222813 Thomas Thrainer
                         }])
296 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
297 66222813 Thomas Thrainer
      op, "No netparams found for network .*.")
298 66222813 Thomas Thrainer
299 66222813 Thomas Thrainer
  def testIpNotInNetwork(self):
300 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
301 66222813 Thomas Thrainer
                         nics=[{
302 11414807 Klaus Aehlig
                           constants.INIC_IP: "203.0.113.1",
303 66222813 Thomas Thrainer
                           constants.INIC_NETWORK: self.net.name
304 66222813 Thomas Thrainer
                         }])
305 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
306 66222813 Thomas Thrainer
      op, "IP address .* already in use or does not belong to network .*")
307 66222813 Thomas Thrainer
308 66222813 Thomas Thrainer
  def testMixAdoptAndNotAdopt(self):
309 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
310 66222813 Thomas Thrainer
                         disk_template=constants.DT_PLAIN,
311 66222813 Thomas Thrainer
                         disks=[{
312 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "lv1"
313 66222813 Thomas Thrainer
                         }, {}])
314 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
315 66222813 Thomas Thrainer
      op, "Either all disks are adopted or none is")
316 66222813 Thomas Thrainer
317 66222813 Thomas Thrainer
  def testMustAdoptWithoutAdopt(self):
318 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
319 66222813 Thomas Thrainer
                         disk_template=constants.DT_BLOCK,
320 66222813 Thomas Thrainer
                         disks=[{}])
321 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
322 66222813 Thomas Thrainer
      op, "Disk template blockdev requires disk adoption, but no 'adopt'"
323 66222813 Thomas Thrainer
          " parameter given")
324 66222813 Thomas Thrainer
325 66222813 Thomas Thrainer
  def testDontAdoptWithAdopt(self):
326 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
327 66222813 Thomas Thrainer
                         disk_template=constants.DT_DRBD8,
328 66222813 Thomas Thrainer
                         disks=[{
329 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "lv1"
330 66222813 Thomas Thrainer
                         }])
331 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
332 66222813 Thomas Thrainer
      op, "Disk adoption is not supported for the 'drbd' disk template")
333 66222813 Thomas Thrainer
334 66222813 Thomas Thrainer
  def testAdoptWithIAllocator(self):
335 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
336 66222813 Thomas Thrainer
                         disk_template=constants.DT_PLAIN,
337 66222813 Thomas Thrainer
                         disks=[{
338 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "lv1"
339 66222813 Thomas Thrainer
                         }],
340 66222813 Thomas Thrainer
                         iallocator="mock")
341 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
342 66222813 Thomas Thrainer
      op, "Disk adoption not allowed with an iallocator script")
343 66222813 Thomas Thrainer
344 66222813 Thomas Thrainer
  def testAdoptWithImport(self):
345 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
346 66222813 Thomas Thrainer
                         disk_template=constants.DT_PLAIN,
347 66222813 Thomas Thrainer
                         disks=[{
348 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "lv1"
349 66222813 Thomas Thrainer
                         }],
350 66222813 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT)
351 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
352 66222813 Thomas Thrainer
      op, "Disk adoption not allowed for instance import")
353 66222813 Thomas Thrainer
354 66222813 Thomas Thrainer
  def testArgumentCombinations(self):
355 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
356 66222813 Thomas Thrainer
                         # start flag will be flipped
357 66222813 Thomas Thrainer
                         no_install=True,
358 66222813 Thomas Thrainer
                         start=True,
359 66222813 Thomas Thrainer
                         # no allowed combination
360 66222813 Thomas Thrainer
                         ip_check=True,
361 66222813 Thomas Thrainer
                         name_check=False)
362 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
363 66222813 Thomas Thrainer
      op, "Cannot do IP address check without a name check")
364 66222813 Thomas Thrainer
365 66222813 Thomas Thrainer
  def testInvalidFileDriver(self):
366 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
367 66222813 Thomas Thrainer
                         file_driver="invalid_file_driver")
368 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
369 66222813 Thomas Thrainer
      op, "Parameter 'OP_INSTANCE_CREATE.file_driver' fails validation")
370 66222813 Thomas Thrainer
371 66222813 Thomas Thrainer
  def testMissingSecondaryNode(self):
372 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
373 66222813 Thomas Thrainer
                         pnode=self.master.name,
374 66222813 Thomas Thrainer
                         disk_template=constants.DT_DRBD8)
375 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
376 66222813 Thomas Thrainer
      op, "The networked disk templates need a mirror node")
377 66222813 Thomas Thrainer
378 66222813 Thomas Thrainer
  def testIgnoredSecondaryNode(self):
379 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
380 66222813 Thomas Thrainer
                         pnode=self.master.name,
381 66222813 Thomas Thrainer
                         snode=self.node1.name,
382 66222813 Thomas Thrainer
                         disk_template=constants.DT_PLAIN)
383 66222813 Thomas Thrainer
    try:
384 66222813 Thomas Thrainer
      self.ExecOpCode(op)
385 66222813 Thomas Thrainer
    except Exception:
386 66222813 Thomas Thrainer
      pass
387 66222813 Thomas Thrainer
    self.mcpu.assertLogContainsRegex(
388 66222813 Thomas Thrainer
      "Secondary node will be ignored on non-mirrored disk template")
389 66222813 Thomas Thrainer
390 66222813 Thomas Thrainer
  def testMissingOsType(self):
391 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
392 66222813 Thomas Thrainer
                         os_type=self.REMOVE)
393 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "No guest OS specified")
394 66222813 Thomas Thrainer
395 66222813 Thomas Thrainer
  def testBlacklistedOs(self):
396 66222813 Thomas Thrainer
    self.cluster.blacklisted_os = [self.os_name_variant]
397 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op)
398 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
399 66222813 Thomas Thrainer
      op, "Guest OS .* is not allowed for installation")
400 66222813 Thomas Thrainer
401 66222813 Thomas Thrainer
  def testMissingDiskTemplate(self):
402 66222813 Thomas Thrainer
    self.cluster.enabled_disk_templates = [constants.DT_DISKLESS]
403 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
404 66222813 Thomas Thrainer
                         disk_template=self.REMOVE)
405 66222813 Thomas Thrainer
    self.ExecOpCode(op)
406 66222813 Thomas Thrainer
407 66222813 Thomas Thrainer
  def testExistingInstance(self):
408 66222813 Thomas Thrainer
    inst = self.cfg.AddNewInstance()
409 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
410 66222813 Thomas Thrainer
                         instance_name=inst.name)
411 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
412 66222813 Thomas Thrainer
      op, "Instance .* is already in the cluster")
413 66222813 Thomas Thrainer
414 66222813 Thomas Thrainer
  def testPlainInstance(self):
415 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op)
416 66222813 Thomas Thrainer
    self.ExecOpCode(op)
417 66222813 Thomas Thrainer
418 66222813 Thomas Thrainer
  def testPlainIAllocator(self):
419 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
420 66222813 Thomas Thrainer
                         pnode=self.REMOVE,
421 66222813 Thomas Thrainer
                         iallocator="mock")
422 66222813 Thomas Thrainer
    self.ExecOpCode(op)
423 66222813 Thomas Thrainer
424 66222813 Thomas Thrainer
  def testIAllocatorOpportunisticLocking(self):
425 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
426 66222813 Thomas Thrainer
                         pnode=self.REMOVE,
427 66222813 Thomas Thrainer
                         iallocator="mock",
428 66222813 Thomas Thrainer
                         opportunistic_locking=True)
429 66222813 Thomas Thrainer
    self.ExecOpCode(op)
430 66222813 Thomas Thrainer
431 66222813 Thomas Thrainer
  def testFailingIAllocator(self):
432 66222813 Thomas Thrainer
    self.iallocator_cls.return_value.success = False
433 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
434 66222813 Thomas Thrainer
                         pnode=self.REMOVE,
435 66222813 Thomas Thrainer
                         iallocator="mock")
436 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
437 66222813 Thomas Thrainer
      op, "Can't compute nodes using iallocator")
438 66222813 Thomas Thrainer
439 66222813 Thomas Thrainer
  def testDrbdInstance(self):
440 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.drbd_op)
441 66222813 Thomas Thrainer
    self.ExecOpCode(op)
442 66222813 Thomas Thrainer
443 66222813 Thomas Thrainer
  def testDrbdIAllocator(self):
444 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.drbd_op,
445 66222813 Thomas Thrainer
                         pnode=self.REMOVE,
446 66222813 Thomas Thrainer
                         snode=self.REMOVE,
447 66222813 Thomas Thrainer
                         iallocator="mock")
448 66222813 Thomas Thrainer
    self.ExecOpCode(op)
449 66222813 Thomas Thrainer
450 66222813 Thomas Thrainer
  def testFileInstance(self):
451 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.file_op)
452 66222813 Thomas Thrainer
    self.ExecOpCode(op)
453 66222813 Thomas Thrainer
454 66222813 Thomas Thrainer
  def testFileInstanceNoClusterStorage(self):
455 66222813 Thomas Thrainer
    self.cluster.file_storage_dir = None
456 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.file_op)
457 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
458 66222813 Thomas Thrainer
      op, "Cluster file storage dir not defined")
459 66222813 Thomas Thrainer
460 66222813 Thomas Thrainer
  def testFileInstanceAdditionalPath(self):
461 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.file_op,
462 66222813 Thomas Thrainer
                         file_storage_dir="mock_dir")
463 66222813 Thomas Thrainer
    self.ExecOpCode(op)
464 66222813 Thomas Thrainer
465 66222813 Thomas Thrainer
  def testIdentifyDefaults(self):
466 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
467 66222813 Thomas Thrainer
                         hvparams={
468 66222813 Thomas Thrainer
                           constants.HV_BOOT_ORDER: "cd"
469 66222813 Thomas Thrainer
                         },
470 66222813 Thomas Thrainer
                         beparams=constants.BEC_DEFAULTS.copy(),
471 66222813 Thomas Thrainer
                         nics=[{
472 66222813 Thomas Thrainer
                           constants.NIC_MODE: constants.NIC_MODE_BRIDGED
473 66222813 Thomas Thrainer
                         }],
474 66222813 Thomas Thrainer
                         osparams={
475 66222813 Thomas Thrainer
                           self.os_name_variant: {}
476 66222813 Thomas Thrainer
                         },
477 66222813 Thomas Thrainer
                         identify_defaults=True)
478 66222813 Thomas Thrainer
    self.ExecOpCode(op)
479 66222813 Thomas Thrainer
480 66222813 Thomas Thrainer
    inst = self.cfg.GetAllInstancesInfo().values()[0]
481 66222813 Thomas Thrainer
    self.assertEqual(0, len(inst.hvparams))
482 66222813 Thomas Thrainer
    self.assertEqual(0, len(inst.beparams))
483 66222813 Thomas Thrainer
    assert self.os_name_variant not in inst.osparams or \
484 66222813 Thomas Thrainer
            len(inst.osparams[self.os_name_variant]) == 0
485 66222813 Thomas Thrainer
486 66222813 Thomas Thrainer
  def testOfflineNode(self):
487 66222813 Thomas Thrainer
    self.node1.offline = True
488 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
489 66222813 Thomas Thrainer
                         pnode=self.node1.name)
490 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot use offline primary node")
491 66222813 Thomas Thrainer
492 66222813 Thomas Thrainer
  def testDrainedNode(self):
493 66222813 Thomas Thrainer
    self.node1.drained = True
494 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
495 66222813 Thomas Thrainer
                         pnode=self.node1.name)
496 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot use drained primary node")
497 66222813 Thomas Thrainer
498 66222813 Thomas Thrainer
  def testNonVmCapableNode(self):
499 66222813 Thomas Thrainer
    self.node1.vm_capable = False
500 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
501 66222813 Thomas Thrainer
                         pnode=self.node1.name)
502 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
503 66222813 Thomas Thrainer
      op, "Cannot use non-vm_capable primary node")
504 66222813 Thomas Thrainer
505 66222813 Thomas Thrainer
  def testNonEnabledHypervisor(self):
506 66222813 Thomas Thrainer
    self.cluster.enabled_hypervisors = [constants.HT_XEN_HVM]
507 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
508 66222813 Thomas Thrainer
                         hypervisor=constants.HT_FAKE)
509 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
510 66222813 Thomas Thrainer
      op, "Selected hypervisor .* not enabled in the cluster")
511 66222813 Thomas Thrainer
512 66222813 Thomas Thrainer
  def testAddTag(self):
513 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
514 66222813 Thomas Thrainer
                         tags=["tag"])
515 66222813 Thomas Thrainer
    self.ExecOpCode(op)
516 66222813 Thomas Thrainer
517 66222813 Thomas Thrainer
  def testInvalidTag(self):
518 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op,
519 66222813 Thomas Thrainer
                         tags=["too_long" * 20])
520 66222813 Thomas Thrainer
    self.ExecOpCodeExpectException(op, errors.TagError, "Tag too long")
521 66222813 Thomas Thrainer
522 66222813 Thomas Thrainer
  def testPingableInstanceName(self):
523 66222813 Thomas Thrainer
    self.netutils_mod.TcpPing.return_value = True
524 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.diskless_op)
525 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
526 66222813 Thomas Thrainer
      op, "IP .* of instance diskless.test.com already in use")
527 66222813 Thomas Thrainer
528 66222813 Thomas Thrainer
  def testPrimaryIsSecondaryNode(self):
529 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.drbd_op,
530 66222813 Thomas Thrainer
                         snode=self.drbd_op.pnode)
531 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
532 66222813 Thomas Thrainer
      op, "The secondary node cannot be the primary node")
533 66222813 Thomas Thrainer
534 66222813 Thomas Thrainer
  def testPrimarySecondaryDifferentNodeGroups(self):
535 66222813 Thomas Thrainer
    group = self.cfg.AddNewNodeGroup()
536 66222813 Thomas Thrainer
    self.node2.group = group.uuid
537 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.drbd_op)
538 66222813 Thomas Thrainer
    self.ExecOpCode(op)
539 66222813 Thomas Thrainer
    self.mcpu.assertLogContainsRegex(
540 66222813 Thomas Thrainer
      "The primary and secondary nodes are in two different node groups")
541 66222813 Thomas Thrainer
542 66222813 Thomas Thrainer
  def testExclusiveStorageUnsupportedDiskTemplate(self):
543 66222813 Thomas Thrainer
    self.node1.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
544 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.drbd_op)
545 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
546 66222813 Thomas Thrainer
      op, "Disk template drbd not supported with exclusive storage")
547 66222813 Thomas Thrainer
548 66222813 Thomas Thrainer
  def testAdoptPlain(self):
549 66222813 Thomas Thrainer
    self.rpc.call_lv_list.return_value = \
550 66222813 Thomas Thrainer
      self.RpcResultsBuilder() \
551 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.master, {
552 66222813 Thomas Thrainer
          "xenvg/mock_disk_1": (10000, None, False)
553 66222813 Thomas Thrainer
        }) \
554 66222813 Thomas Thrainer
        .Build()
555 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op)
556 66222813 Thomas Thrainer
    op.disks[0].update({constants.IDISK_ADOPT: "mock_disk_1"})
557 66222813 Thomas Thrainer
    self.ExecOpCode(op)
558 66222813 Thomas Thrainer
559 66222813 Thomas Thrainer
  def testAdoptPlainMissingLv(self):
560 66222813 Thomas Thrainer
    self.rpc.call_lv_list.return_value = \
561 66222813 Thomas Thrainer
      self.RpcResultsBuilder() \
562 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.master, {}) \
563 66222813 Thomas Thrainer
        .Build()
564 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op)
565 66222813 Thomas Thrainer
    op.disks[0].update({constants.IDISK_ADOPT: "mock_disk_1"})
566 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Missing logical volume")
567 66222813 Thomas Thrainer
568 66222813 Thomas Thrainer
  def testAdoptPlainOnlineLv(self):
569 66222813 Thomas Thrainer
    self.rpc.call_lv_list.return_value = \
570 66222813 Thomas Thrainer
      self.RpcResultsBuilder() \
571 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.master, {
572 66222813 Thomas Thrainer
          "xenvg/mock_disk_1": (10000, None, True)
573 66222813 Thomas Thrainer
        }) \
574 66222813 Thomas Thrainer
        .Build()
575 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op)
576 66222813 Thomas Thrainer
    op.disks[0].update({constants.IDISK_ADOPT: "mock_disk_1"})
577 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
578 66222813 Thomas Thrainer
      op, "Online logical volumes found, cannot adopt")
579 66222813 Thomas Thrainer
580 66222813 Thomas Thrainer
  def testAdoptBlock(self):
581 66222813 Thomas Thrainer
    self.rpc.call_bdev_sizes.return_value = \
582 66222813 Thomas Thrainer
      self.RpcResultsBuilder() \
583 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.master, {
584 66222813 Thomas Thrainer
          "/dev/disk/block0": 10000
585 66222813 Thomas Thrainer
        }) \
586 66222813 Thomas Thrainer
        .Build()
587 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.block_op)
588 66222813 Thomas Thrainer
    self.ExecOpCode(op)
589 66222813 Thomas Thrainer
590 66222813 Thomas Thrainer
  def testAdoptBlockDuplicateNames(self):
591 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.block_op,
592 66222813 Thomas Thrainer
                         disks=[{
593 66222813 Thomas Thrainer
                           constants.IDISK_SIZE: 0,
594 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "/dev/disk/block0"
595 66222813 Thomas Thrainer
                         }, {
596 66222813 Thomas Thrainer
                           constants.IDISK_SIZE: 0,
597 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "/dev/disk/block0"
598 66222813 Thomas Thrainer
                         }])
599 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
600 66222813 Thomas Thrainer
      op, "Duplicate disk names given for adoption")
601 66222813 Thomas Thrainer
602 66222813 Thomas Thrainer
  def testAdoptBlockInvalidNames(self):
603 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.block_op,
604 66222813 Thomas Thrainer
                         disks=[{
605 66222813 Thomas Thrainer
                           constants.IDISK_SIZE: 0,
606 66222813 Thomas Thrainer
                           constants.IDISK_ADOPT: "/invalid/block0"
607 66222813 Thomas Thrainer
                         }])
608 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
609 66222813 Thomas Thrainer
      op, "Device node.* lie outside .* and cannot be adopted")
610 66222813 Thomas Thrainer
611 66222813 Thomas Thrainer
  def testAdoptBlockMissingDisk(self):
612 66222813 Thomas Thrainer
    self.rpc.call_bdev_sizes.return_value = \
613 66222813 Thomas Thrainer
      self.RpcResultsBuilder() \
614 66222813 Thomas Thrainer
        .AddSuccessfulNode(self.master, {}) \
615 66222813 Thomas Thrainer
        .Build()
616 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.block_op)
617 66222813 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Missing block device")
618 66222813 Thomas Thrainer
619 66222813 Thomas Thrainer
  def testNoWaitForSyncDrbd(self):
620 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.drbd_op,
621 66222813 Thomas Thrainer
                         wait_for_sync=False)
622 66222813 Thomas Thrainer
    self.ExecOpCode(op)
623 66222813 Thomas Thrainer
624 66222813 Thomas Thrainer
  def testNoWaitForSyncPlain(self):
625 66222813 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
626 66222813 Thomas Thrainer
                         wait_for_sync=False)
627 66222813 Thomas Thrainer
    self.ExecOpCode(op)
628 66222813 Thomas Thrainer
629 72bac0c5 Thomas Thrainer
  def testImportPlainFromGivenSrcNode(self):
630 72bac0c5 Thomas Thrainer
    exp_info = """
631 72bac0c5 Thomas Thrainer
[export]
632 72bac0c5 Thomas Thrainer
version=0
633 72bac0c5 Thomas Thrainer
os=mock_os
634 72bac0c5 Thomas Thrainer
[instance]
635 72bac0c5 Thomas Thrainer
name=old_name.example.com
636 72bac0c5 Thomas Thrainer
"""
637 72bac0c5 Thomas Thrainer
638 72bac0c5 Thomas Thrainer
    self.rpc.call_export_info.return_value = \
639 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
640 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, exp_info)
641 72bac0c5 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
642 72bac0c5 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT,
643 72bac0c5 Thomas Thrainer
                         src_node=self.master.name)
644 72bac0c5 Thomas Thrainer
    self.ExecOpCode(op)
645 72bac0c5 Thomas Thrainer
646 72bac0c5 Thomas Thrainer
  def testImportPlainWithoutSrcNodeNotFound(self):
647 72bac0c5 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
648 72bac0c5 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT)
649 72bac0c5 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
650 72bac0c5 Thomas Thrainer
      op, "No export found for relative path")
651 72bac0c5 Thomas Thrainer
652 72bac0c5 Thomas Thrainer
  def testImportPlainWithoutSrcNode(self):
653 72bac0c5 Thomas Thrainer
    exp_info = """
654 72bac0c5 Thomas Thrainer
[export]
655 72bac0c5 Thomas Thrainer
version=0
656 72bac0c5 Thomas Thrainer
os=mock_os
657 72bac0c5 Thomas Thrainer
[instance]
658 72bac0c5 Thomas Thrainer
name=old_name.example.com
659 72bac0c5 Thomas Thrainer
"""
660 72bac0c5 Thomas Thrainer
661 72bac0c5 Thomas Thrainer
    self.rpc.call_export_list.return_value = \
662 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
663 72bac0c5 Thomas Thrainer
        .AddSuccessfulNode(self.master, {"mock_path": {}}) \
664 72bac0c5 Thomas Thrainer
        .Build()
665 72bac0c5 Thomas Thrainer
    self.rpc.call_export_info.return_value = \
666 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
667 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, exp_info)
668 72bac0c5 Thomas Thrainer
669 72bac0c5 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
670 72bac0c5 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT,
671 72bac0c5 Thomas Thrainer
                         src_path="mock_path")
672 72bac0c5 Thomas Thrainer
    self.ExecOpCode(op)
673 72bac0c5 Thomas Thrainer
674 72bac0c5 Thomas Thrainer
  def testImportPlainCorruptExportInfo(self):
675 72bac0c5 Thomas Thrainer
    exp_info = ""
676 72bac0c5 Thomas Thrainer
    self.rpc.call_export_info.return_value = \
677 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
678 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, exp_info)
679 72bac0c5 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
680 72bac0c5 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT,
681 72bac0c5 Thomas Thrainer
                         src_node=self.master.name)
682 72bac0c5 Thomas Thrainer
    self.ExecOpCodeExpectException(op, errors.ProgrammerError,
683 72bac0c5 Thomas Thrainer
                                   "Corrupted export config")
684 72bac0c5 Thomas Thrainer
685 72bac0c5 Thomas Thrainer
  def testImportPlainWrongExportInfoVersion(self):
686 72bac0c5 Thomas Thrainer
    exp_info = """
687 72bac0c5 Thomas Thrainer
[export]
688 72bac0c5 Thomas Thrainer
version=1
689 72bac0c5 Thomas Thrainer
"""
690 72bac0c5 Thomas Thrainer
    self.rpc.call_export_info.return_value = \
691 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
692 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, exp_info)
693 72bac0c5 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
694 72bac0c5 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT,
695 72bac0c5 Thomas Thrainer
                         src_node=self.master.name)
696 72bac0c5 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Wrong export version")
697 72bac0c5 Thomas Thrainer
698 72bac0c5 Thomas Thrainer
  def testImportPlainWithParametersAndImport(self):
699 72bac0c5 Thomas Thrainer
    exp_info = """
700 72bac0c5 Thomas Thrainer
[export]
701 72bac0c5 Thomas Thrainer
version=0
702 72bac0c5 Thomas Thrainer
os=mock_os
703 72bac0c5 Thomas Thrainer
[instance]
704 72bac0c5 Thomas Thrainer
name=old_name.example.com
705 72bac0c5 Thomas Thrainer
disk0_size=1024
706 72bac0c5 Thomas Thrainer
disk1_size=1500
707 72bac0c5 Thomas Thrainer
disk1_dump=mock_path
708 72bac0c5 Thomas Thrainer
nic0_mode=bridged
709 72bac0c5 Thomas Thrainer
nic0_link=br_mock
710 72bac0c5 Thomas Thrainer
nic0_mac=f6:ab:f4:45:d1:af
711 4256f8fe Sebastian Gebhard
nic0_ip=192.0.2.1
712 72bac0c5 Thomas Thrainer
tags=tag1 tag2
713 72bac0c5 Thomas Thrainer
hypervisor=xen-hvm
714 72bac0c5 Thomas Thrainer
[hypervisor]
715 72bac0c5 Thomas Thrainer
boot_order=cd
716 72bac0c5 Thomas Thrainer
[backend]
717 72bac0c5 Thomas Thrainer
memory=1024
718 72bac0c5 Thomas Thrainer
vcpus=8
719 72bac0c5 Thomas Thrainer
[os]
720 72bac0c5 Thomas Thrainer
param1=val1
721 72bac0c5 Thomas Thrainer
"""
722 72bac0c5 Thomas Thrainer
723 72bac0c5 Thomas Thrainer
    self.rpc.call_export_info.return_value = \
724 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
725 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, exp_info)
726 72bac0c5 Thomas Thrainer
    self.rpc.call_import_start.return_value = \
727 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
728 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, "daemon_name")
729 72bac0c5 Thomas Thrainer
    self.rpc.call_impexp_status.return_value = \
730 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
731 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master,
732 72bac0c5 Thomas Thrainer
                                    [
733 72bac0c5 Thomas Thrainer
                                      objects.ImportExportStatus(exit_status=0)
734 72bac0c5 Thomas Thrainer
                                    ])
735 72bac0c5 Thomas Thrainer
    self.rpc.call_impexp_cleanup.return_value = \
736 72bac0c5 Thomas Thrainer
      self.RpcResultsBuilder() \
737 72bac0c5 Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, True)
738 72bac0c5 Thomas Thrainer
739 72bac0c5 Thomas Thrainer
    op = self.CopyOpCode(self.plain_op,
740 72bac0c5 Thomas Thrainer
                         disks=[],
741 72bac0c5 Thomas Thrainer
                         nics=[],
742 72bac0c5 Thomas Thrainer
                         tags=[],
743 72bac0c5 Thomas Thrainer
                         hypervisor=None,
744 72bac0c5 Thomas Thrainer
                         hvparams={},
745 72bac0c5 Thomas Thrainer
                         mode=constants.INSTANCE_IMPORT,
746 72bac0c5 Thomas Thrainer
                         src_node=self.master.name)
747 72bac0c5 Thomas Thrainer
    self.ExecOpCode(op)
748 72bac0c5 Thomas Thrainer
749 72bac0c5 Thomas Thrainer
750 66222813 Thomas Thrainer
class TestCheckOSVariant(CmdlibTestCase):
751 66222813 Thomas Thrainer
  def testNoVariantsSupported(self):
752 66222813 Thomas Thrainer
    os = self.cfg.CreateOs(supported_variants=[])
753 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, instance._CheckOSVariant,
754 66222813 Thomas Thrainer
                      os, "os+variant")
755 66222813 Thomas Thrainer
756 66222813 Thomas Thrainer
  def testNoVariantGiven(self):
757 66222813 Thomas Thrainer
    os = self.cfg.CreateOs(supported_variants=["default"])
758 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, instance._CheckOSVariant,
759 66222813 Thomas Thrainer
                      os, "os")
760 66222813 Thomas Thrainer
761 66222813 Thomas Thrainer
  def testWrongVariantGiven(self):
762 66222813 Thomas Thrainer
    os = self.cfg.CreateOs(supported_variants=["default"])
763 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, instance._CheckOSVariant,
764 66222813 Thomas Thrainer
                      os, "os+wrong_variant")
765 66222813 Thomas Thrainer
766 66222813 Thomas Thrainer
  def testOkWithVariant(self):
767 66222813 Thomas Thrainer
    os = self.cfg.CreateOs(supported_variants=["default"])
768 66222813 Thomas Thrainer
    instance._CheckOSVariant(os, "os+default")
769 66222813 Thomas Thrainer
770 66222813 Thomas Thrainer
  def testOkWithoutVariant(self):
771 66222813 Thomas Thrainer
    os = self.cfg.CreateOs(supported_variants=[])
772 66222813 Thomas Thrainer
    instance._CheckOSVariant(os, "os")
773 66222813 Thomas Thrainer
774 66222813 Thomas Thrainer
775 66222813 Thomas Thrainer
class TestCheckTargetNodeIPolicy(TestLUInstanceCreate):
776 66222813 Thomas Thrainer
  def setUp(self):
777 66222813 Thomas Thrainer
    super(TestCheckTargetNodeIPolicy, self).setUp()
778 66222813 Thomas Thrainer
779 66222813 Thomas Thrainer
    self.op = self.diskless_op
780 66222813 Thomas Thrainer
781 66222813 Thomas Thrainer
    self.instance = self.cfg.AddNewInstance()
782 66222813 Thomas Thrainer
    self.target_group = self.cfg.AddNewNodeGroup()
783 66222813 Thomas Thrainer
    self.target_node = self.cfg.AddNewNode(group=self.target_group)
784 66222813 Thomas Thrainer
785 66222813 Thomas Thrainer
  @withLockedLU
786 66222813 Thomas Thrainer
  def testNoViolation(self, lu):
787 66222813 Thomas Thrainer
    compute_recoder = mock.Mock(return_value=[])
788 66222813 Thomas Thrainer
    instance.CheckTargetNodeIPolicy(lu, NotImplemented, self.instance,
789 66222813 Thomas Thrainer
                                    self.target_node, NotImplemented,
790 66222813 Thomas Thrainer
                                    _compute_fn=compute_recoder)
791 66222813 Thomas Thrainer
    self.assertTrue(compute_recoder.called)
792 66222813 Thomas Thrainer
    self.mcpu.assertLogIsEmpty()
793 66222813 Thomas Thrainer
794 66222813 Thomas Thrainer
  @withLockedLU
795 66222813 Thomas Thrainer
  def testNoIgnore(self, lu):
796 66222813 Thomas Thrainer
    compute_recoder = mock.Mock(return_value=["mem_size not in range"])
797 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, instance.CheckTargetNodeIPolicy,
798 66222813 Thomas Thrainer
                      lu, NotImplemented, self.instance,
799 66222813 Thomas Thrainer
                      self.target_node, NotImplemented,
800 66222813 Thomas Thrainer
                      _compute_fn=compute_recoder)
801 66222813 Thomas Thrainer
    self.assertTrue(compute_recoder.called)
802 66222813 Thomas Thrainer
    self.mcpu.assertLogIsEmpty()
803 66222813 Thomas Thrainer
804 66222813 Thomas Thrainer
  @withLockedLU
805 66222813 Thomas Thrainer
  def testIgnoreViolation(self, lu):
806 66222813 Thomas Thrainer
    compute_recoder = mock.Mock(return_value=["mem_size not in range"])
807 66222813 Thomas Thrainer
    instance.CheckTargetNodeIPolicy(lu, NotImplemented, self.instance,
808 66222813 Thomas Thrainer
                                    self.target_node, NotImplemented,
809 66222813 Thomas Thrainer
                                    ignore=True, _compute_fn=compute_recoder)
810 66222813 Thomas Thrainer
    self.assertTrue(compute_recoder.called)
811 66222813 Thomas Thrainer
    msg = ("Instance does not meet target node group's .* instance policy:"
812 66222813 Thomas Thrainer
           " mem_size not in range")
813 66222813 Thomas Thrainer
    self.mcpu.assertLogContainsRegex(msg)
814 66222813 Thomas Thrainer
815 66222813 Thomas Thrainer
816 66222813 Thomas Thrainer
class TestApplyContainerMods(unittest.TestCase):
817 66222813 Thomas Thrainer
  def testEmptyContainer(self):
818 66222813 Thomas Thrainer
    container = []
819 66222813 Thomas Thrainer
    chgdesc = []
820 66222813 Thomas Thrainer
    instance._ApplyContainerMods("test", container, chgdesc, [], None, None,
821 66222813 Thomas Thrainer
                                 None)
822 66222813 Thomas Thrainer
    self.assertEqual(container, [])
823 66222813 Thomas Thrainer
    self.assertEqual(chgdesc, [])
824 66222813 Thomas Thrainer
825 66222813 Thomas Thrainer
  def testAdd(self):
826 66222813 Thomas Thrainer
    container = []
827 66222813 Thomas Thrainer
    chgdesc = []
828 66222813 Thomas Thrainer
    mods = instance._PrepareContainerMods([
829 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "Hello"),
830 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "World"),
831 66222813 Thomas Thrainer
      (constants.DDM_ADD, 0, "Start"),
832 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "End"),
833 66222813 Thomas Thrainer
      ], None)
834 66222813 Thomas Thrainer
    instance._ApplyContainerMods("test", container, chgdesc, mods,
835 66222813 Thomas Thrainer
                                 None, None, None)
836 66222813 Thomas Thrainer
    self.assertEqual(container, ["Start", "Hello", "World", "End"])
837 66222813 Thomas Thrainer
    self.assertEqual(chgdesc, [])
838 66222813 Thomas Thrainer
839 66222813 Thomas Thrainer
    mods = instance._PrepareContainerMods([
840 66222813 Thomas Thrainer
      (constants.DDM_ADD, 0, "zero"),
841 66222813 Thomas Thrainer
      (constants.DDM_ADD, 3, "Added"),
842 66222813 Thomas Thrainer
      (constants.DDM_ADD, 5, "four"),
843 66222813 Thomas Thrainer
      (constants.DDM_ADD, 7, "xyz"),
844 66222813 Thomas Thrainer
      ], None)
845 66222813 Thomas Thrainer
    instance._ApplyContainerMods("test", container, chgdesc, mods,
846 66222813 Thomas Thrainer
                                 None, None, None)
847 66222813 Thomas Thrainer
    self.assertEqual(container,
848 66222813 Thomas Thrainer
                     ["zero", "Start", "Hello", "Added", "World", "four",
849 66222813 Thomas Thrainer
                      "End", "xyz"])
850 66222813 Thomas Thrainer
    self.assertEqual(chgdesc, [])
851 66222813 Thomas Thrainer
852 66222813 Thomas Thrainer
    for idx in [-2, len(container) + 1]:
853 66222813 Thomas Thrainer
      mods = instance._PrepareContainerMods([
854 66222813 Thomas Thrainer
        (constants.DDM_ADD, idx, "error"),
855 66222813 Thomas Thrainer
        ], None)
856 66222813 Thomas Thrainer
      self.assertRaises(IndexError, instance._ApplyContainerMods,
857 66222813 Thomas Thrainer
                        "test", container, None, mods, None, None, None)
858 66222813 Thomas Thrainer
859 66222813 Thomas Thrainer
  def testRemoveError(self):
860 66222813 Thomas Thrainer
    for idx in [0, 1, 2, 100, -1, -4]:
861 66222813 Thomas Thrainer
      mods = instance._PrepareContainerMods([
862 66222813 Thomas Thrainer
        (constants.DDM_REMOVE, idx, None),
863 66222813 Thomas Thrainer
        ], None)
864 66222813 Thomas Thrainer
      self.assertRaises(IndexError, instance._ApplyContainerMods,
865 66222813 Thomas Thrainer
                        "test", [], None, mods, None, None, None)
866 66222813 Thomas Thrainer
867 66222813 Thomas Thrainer
    mods = instance._PrepareContainerMods([
868 66222813 Thomas Thrainer
      (constants.DDM_REMOVE, 0, object()),
869 66222813 Thomas Thrainer
      ], None)
870 66222813 Thomas Thrainer
    self.assertRaises(AssertionError, instance._ApplyContainerMods,
871 66222813 Thomas Thrainer
                      "test", [""], None, mods, None, None, None)
872 66222813 Thomas Thrainer
873 66222813 Thomas Thrainer
  def testAddError(self):
874 66222813 Thomas Thrainer
    for idx in range(-100, -1) + [100]:
875 66222813 Thomas Thrainer
      mods = instance._PrepareContainerMods([
876 66222813 Thomas Thrainer
        (constants.DDM_ADD, idx, None),
877 66222813 Thomas Thrainer
        ], None)
878 66222813 Thomas Thrainer
      self.assertRaises(IndexError, instance._ApplyContainerMods,
879 66222813 Thomas Thrainer
                        "test", [], None, mods, None, None, None)
880 66222813 Thomas Thrainer
881 66222813 Thomas Thrainer
  def testRemove(self):
882 66222813 Thomas Thrainer
    container = ["item 1", "item 2"]
883 66222813 Thomas Thrainer
    mods = instance._PrepareContainerMods([
884 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "aaa"),
885 66222813 Thomas Thrainer
      (constants.DDM_REMOVE, -1, None),
886 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "bbb"),
887 66222813 Thomas Thrainer
      ], None)
888 66222813 Thomas Thrainer
    chgdesc = []
889 66222813 Thomas Thrainer
    instance._ApplyContainerMods("test", container, chgdesc, mods,
890 66222813 Thomas Thrainer
                                 None, None, None)
891 66222813 Thomas Thrainer
    self.assertEqual(container, ["item 1", "item 2", "bbb"])
892 66222813 Thomas Thrainer
    self.assertEqual(chgdesc, [
893 66222813 Thomas Thrainer
      ("test/2", "remove"),
894 66222813 Thomas Thrainer
      ])
895 66222813 Thomas Thrainer
896 66222813 Thomas Thrainer
  def testModify(self):
897 66222813 Thomas Thrainer
    container = ["item 1", "item 2"]
898 66222813 Thomas Thrainer
    mods = instance._PrepareContainerMods([
899 66222813 Thomas Thrainer
      (constants.DDM_MODIFY, -1, "a"),
900 66222813 Thomas Thrainer
      (constants.DDM_MODIFY, 0, "b"),
901 66222813 Thomas Thrainer
      (constants.DDM_MODIFY, 1, "c"),
902 66222813 Thomas Thrainer
      ], None)
903 66222813 Thomas Thrainer
    chgdesc = []
904 66222813 Thomas Thrainer
    instance._ApplyContainerMods("test", container, chgdesc, mods,
905 66222813 Thomas Thrainer
                                 None, None, None)
906 66222813 Thomas Thrainer
    self.assertEqual(container, ["item 1", "item 2"])
907 66222813 Thomas Thrainer
    self.assertEqual(chgdesc, [])
908 66222813 Thomas Thrainer
909 66222813 Thomas Thrainer
    for idx in [-2, len(container) + 1]:
910 66222813 Thomas Thrainer
      mods = instance._PrepareContainerMods([
911 66222813 Thomas Thrainer
        (constants.DDM_MODIFY, idx, "error"),
912 66222813 Thomas Thrainer
        ], None)
913 66222813 Thomas Thrainer
      self.assertRaises(IndexError, instance._ApplyContainerMods,
914 66222813 Thomas Thrainer
                        "test", container, None, mods, None, None, None)
915 66222813 Thomas Thrainer
916 66222813 Thomas Thrainer
  @staticmethod
917 66222813 Thomas Thrainer
  def _CreateTestFn(idx, params, private):
918 66222813 Thomas Thrainer
    private.data = ("add", idx, params)
919 66222813 Thomas Thrainer
    return ((100 * idx, params), [
920 66222813 Thomas Thrainer
      ("test/%s" % idx, hex(idx)),
921 66222813 Thomas Thrainer
      ])
922 66222813 Thomas Thrainer
923 66222813 Thomas Thrainer
  @staticmethod
924 66222813 Thomas Thrainer
  def _ModifyTestFn(idx, item, params, private):
925 66222813 Thomas Thrainer
    private.data = ("modify", idx, params)
926 66222813 Thomas Thrainer
    return [
927 66222813 Thomas Thrainer
      ("test/%s" % idx, "modify %s" % params),
928 66222813 Thomas Thrainer
      ]
929 66222813 Thomas Thrainer
930 66222813 Thomas Thrainer
  @staticmethod
931 66222813 Thomas Thrainer
  def _RemoveTestFn(idx, item, private):
932 66222813 Thomas Thrainer
    private.data = ("remove", idx, item)
933 66222813 Thomas Thrainer
934 66222813 Thomas Thrainer
  def testAddWithCreateFunction(self):
935 66222813 Thomas Thrainer
    container = []
936 66222813 Thomas Thrainer
    chgdesc = []
937 66222813 Thomas Thrainer
    mods = instance._PrepareContainerMods([
938 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "Hello"),
939 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "World"),
940 66222813 Thomas Thrainer
      (constants.DDM_ADD, 0, "Start"),
941 66222813 Thomas Thrainer
      (constants.DDM_ADD, -1, "End"),
942 66222813 Thomas Thrainer
      (constants.DDM_REMOVE, 2, None),
943 66222813 Thomas Thrainer
      (constants.DDM_MODIFY, -1, "foobar"),
944 66222813 Thomas Thrainer
      (constants.DDM_REMOVE, 2, None),
945 66222813 Thomas Thrainer
      (constants.DDM_ADD, 1, "More"),
946 66222813 Thomas Thrainer
      ], mock.Mock)
947 66222813 Thomas Thrainer
    instance._ApplyContainerMods("test", container, chgdesc, mods,
948 66222813 Thomas Thrainer
                                 self._CreateTestFn, self._ModifyTestFn,
949 66222813 Thomas Thrainer
                                 self._RemoveTestFn)
950 66222813 Thomas Thrainer
    self.assertEqual(container, [
951 66222813 Thomas Thrainer
      (000, "Start"),
952 66222813 Thomas Thrainer
      (100, "More"),
953 66222813 Thomas Thrainer
      (000, "Hello"),
954 66222813 Thomas Thrainer
      ])
955 66222813 Thomas Thrainer
    self.assertEqual(chgdesc, [
956 66222813 Thomas Thrainer
      ("test/0", "0x0"),
957 66222813 Thomas Thrainer
      ("test/1", "0x1"),
958 66222813 Thomas Thrainer
      ("test/0", "0x0"),
959 66222813 Thomas Thrainer
      ("test/3", "0x3"),
960 66222813 Thomas Thrainer
      ("test/2", "remove"),
961 66222813 Thomas Thrainer
      ("test/2", "modify foobar"),
962 66222813 Thomas Thrainer
      ("test/2", "remove"),
963 66222813 Thomas Thrainer
      ("test/1", "0x1")
964 66222813 Thomas Thrainer
      ])
965 66222813 Thomas Thrainer
    self.assertTrue(compat.all(op == private.data[0]
966 66222813 Thomas Thrainer
                               for (op, _, _, private) in mods))
967 66222813 Thomas Thrainer
    self.assertEqual([private.data for (op, _, _, private) in mods], [
968 66222813 Thomas Thrainer
      ("add", 0, "Hello"),
969 66222813 Thomas Thrainer
      ("add", 1, "World"),
970 66222813 Thomas Thrainer
      ("add", 0, "Start"),
971 66222813 Thomas Thrainer
      ("add", 3, "End"),
972 66222813 Thomas Thrainer
      ("remove", 2, (100, "World")),
973 66222813 Thomas Thrainer
      ("modify", 2, "foobar"),
974 66222813 Thomas Thrainer
      ("remove", 2, (300, "End")),
975 66222813 Thomas Thrainer
      ("add", 1, "More"),
976 66222813 Thomas Thrainer
      ])
977 66222813 Thomas Thrainer
978 66222813 Thomas Thrainer
979 66222813 Thomas Thrainer
class _FakeConfigForGenDiskTemplate(ConfigMock):
980 66222813 Thomas Thrainer
  def __init__(self):
981 66222813 Thomas Thrainer
    super(_FakeConfigForGenDiskTemplate, self).__init__()
982 66222813 Thomas Thrainer
983 66222813 Thomas Thrainer
    self._unique_id = itertools.count()
984 66222813 Thomas Thrainer
    self._drbd_minor = itertools.count(20)
985 66222813 Thomas Thrainer
    self._port = itertools.count(constants.FIRST_DRBD_PORT)
986 66222813 Thomas Thrainer
    self._secret = itertools.count()
987 66222813 Thomas Thrainer
988 66222813 Thomas Thrainer
  def GenerateUniqueID(self, ec_id):
989 66222813 Thomas Thrainer
    return "ec%s-uq%s" % (ec_id, self._unique_id.next())
990 66222813 Thomas Thrainer
991 66222813 Thomas Thrainer
  def AllocateDRBDMinor(self, nodes, instance):
992 66222813 Thomas Thrainer
    return [self._drbd_minor.next()
993 66222813 Thomas Thrainer
            for _ in nodes]
994 66222813 Thomas Thrainer
995 66222813 Thomas Thrainer
  def AllocatePort(self):
996 66222813 Thomas Thrainer
    return self._port.next()
997 66222813 Thomas Thrainer
998 66222813 Thomas Thrainer
  def GenerateDRBDSecret(self, ec_id):
999 66222813 Thomas Thrainer
    return "ec%s-secret%s" % (ec_id, self._secret.next())
1000 66222813 Thomas Thrainer
1001 66222813 Thomas Thrainer
1002 66222813 Thomas Thrainer
class TestGenerateDiskTemplate(CmdlibTestCase):
1003 66222813 Thomas Thrainer
  def setUp(self):
1004 66222813 Thomas Thrainer
    super(TestGenerateDiskTemplate, self).setUp()
1005 66222813 Thomas Thrainer
1006 66222813 Thomas Thrainer
    self.cfg = _FakeConfigForGenDiskTemplate()
1007 66222813 Thomas Thrainer
    self.cluster.enabled_disk_templates = list(constants.DISK_TEMPLATES)
1008 66222813 Thomas Thrainer
1009 66222813 Thomas Thrainer
    self.nodegroup = self.cfg.AddNewNodeGroup(name="ng")
1010 66222813 Thomas Thrainer
1011 57da0458 Thomas Thrainer
    self.lu = self.GetMockLU()
1012 66222813 Thomas Thrainer
1013 66222813 Thomas Thrainer
  @staticmethod
1014 66222813 Thomas Thrainer
  def GetDiskParams():
1015 66222813 Thomas Thrainer
    return copy.deepcopy(constants.DISK_DT_DEFAULTS)
1016 66222813 Thomas Thrainer
1017 66222813 Thomas Thrainer
  def testWrongDiskTemplate(self):
1018 66222813 Thomas Thrainer
    gdt = instance.GenerateDiskTemplate
1019 66222813 Thomas Thrainer
    disk_template = "##unknown##"
1020 66222813 Thomas Thrainer
1021 66222813 Thomas Thrainer
    assert disk_template not in constants.DISK_TEMPLATES
1022 66222813 Thomas Thrainer
1023 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, gdt, self.lu, disk_template,
1024 66222813 Thomas Thrainer
                      "inst26831.example.com", "node30113.example.com", [], [],
1025 66222813 Thomas Thrainer
                      NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1026 66222813 Thomas Thrainer
                      self.GetDiskParams())
1027 66222813 Thomas Thrainer
1028 66222813 Thomas Thrainer
  def testDiskless(self):
1029 66222813 Thomas Thrainer
    gdt = instance.GenerateDiskTemplate
1030 66222813 Thomas Thrainer
1031 66222813 Thomas Thrainer
    result = gdt(self.lu, constants.DT_DISKLESS, "inst27734.example.com",
1032 66222813 Thomas Thrainer
                 "node30113.example.com", [], [],
1033 66222813 Thomas Thrainer
                 NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1034 66222813 Thomas Thrainer
                 self.GetDiskParams())
1035 66222813 Thomas Thrainer
    self.assertEqual(result, [])
1036 66222813 Thomas Thrainer
1037 66222813 Thomas Thrainer
  def _TestTrivialDisk(self, template, disk_info, base_index, exp_dev_type,
1038 66222813 Thomas Thrainer
                       file_storage_dir=NotImplemented,
1039 66222813 Thomas Thrainer
                       file_driver=NotImplemented):
1040 66222813 Thomas Thrainer
    gdt = instance.GenerateDiskTemplate
1041 66222813 Thomas Thrainer
1042 66222813 Thomas Thrainer
    map(lambda params: utils.ForceDictType(params,
1043 66222813 Thomas Thrainer
                                           constants.IDISK_PARAMS_TYPES),
1044 66222813 Thomas Thrainer
        disk_info)
1045 66222813 Thomas Thrainer
1046 66222813 Thomas Thrainer
    # Check if non-empty list of secondaries is rejected
1047 66222813 Thomas Thrainer
    self.assertRaises(errors.ProgrammerError, gdt, self.lu,
1048 66222813 Thomas Thrainer
                      template, "inst25088.example.com",
1049 66222813 Thomas Thrainer
                      "node185.example.com", ["node323.example.com"], [],
1050 66222813 Thomas Thrainer
                      NotImplemented, NotImplemented, base_index,
1051 66222813 Thomas Thrainer
                      self.lu.LogInfo, self.GetDiskParams())
1052 66222813 Thomas Thrainer
1053 66222813 Thomas Thrainer
    result = gdt(self.lu, template, "inst21662.example.com",
1054 66222813 Thomas Thrainer
                 "node21741.example.com", [],
1055 66222813 Thomas Thrainer
                 disk_info, file_storage_dir, file_driver, base_index,
1056 66222813 Thomas Thrainer
                 self.lu.LogInfo, self.GetDiskParams())
1057 66222813 Thomas Thrainer
1058 66222813 Thomas Thrainer
    for (idx, disk) in enumerate(result):
1059 66222813 Thomas Thrainer
      self.assertTrue(isinstance(disk, objects.Disk))
1060 66222813 Thomas Thrainer
      self.assertEqual(disk.dev_type, exp_dev_type)
1061 66222813 Thomas Thrainer
      self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1062 66222813 Thomas Thrainer
      self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1063 66222813 Thomas Thrainer
      self.assertTrue(disk.children is None)
1064 66222813 Thomas Thrainer
1065 66222813 Thomas Thrainer
    self._CheckIvNames(result, base_index, base_index + len(disk_info))
1066 66222813 Thomas Thrainer
    instance._UpdateIvNames(base_index, result)
1067 66222813 Thomas Thrainer
    self._CheckIvNames(result, base_index, base_index + len(disk_info))
1068 66222813 Thomas Thrainer
1069 66222813 Thomas Thrainer
    return result
1070 66222813 Thomas Thrainer
1071 66222813 Thomas Thrainer
  def _CheckIvNames(self, disks, base_index, end_index):
1072 66222813 Thomas Thrainer
    self.assertEqual(map(operator.attrgetter("iv_name"), disks),
1073 66222813 Thomas Thrainer
                     ["disk/%s" % i for i in range(base_index, end_index)])
1074 66222813 Thomas Thrainer
1075 66222813 Thomas Thrainer
  def testPlain(self):
1076 66222813 Thomas Thrainer
    disk_info = [{
1077 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 1024,
1078 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDWR,
1079 66222813 Thomas Thrainer
      }, {
1080 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 4096,
1081 66222813 Thomas Thrainer
      constants.IDISK_VG: "othervg",
1082 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDWR,
1083 66222813 Thomas Thrainer
      }]
1084 66222813 Thomas Thrainer
1085 66222813 Thomas Thrainer
    result = self._TestTrivialDisk(constants.DT_PLAIN, disk_info, 3,
1086 0c5f1b13 Thomas Thrainer
                                   constants.DT_PLAIN)
1087 66222813 Thomas Thrainer
1088 66222813 Thomas Thrainer
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1089 66222813 Thomas Thrainer
      ("xenvg", "ec1-uq0.disk3"),
1090 66222813 Thomas Thrainer
      ("othervg", "ec1-uq1.disk4"),
1091 66222813 Thomas Thrainer
      ])
1092 66222813 Thomas Thrainer
1093 66222813 Thomas Thrainer
  def testFile(self):
1094 66222813 Thomas Thrainer
    # anything != DT_FILE would do here
1095 66222813 Thomas Thrainer
    self.cluster.enabled_disk_templates = [constants.DT_PLAIN]
1096 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1097 66222813 Thomas Thrainer
                      constants.DT_FILE, [], 0, NotImplemented)
1098 66222813 Thomas Thrainer
    self.assertRaises(errors.OpPrereqError, self._TestTrivialDisk,
1099 66222813 Thomas Thrainer
                      constants.DT_SHARED_FILE, [], 0, NotImplemented)
1100 66222813 Thomas Thrainer
1101 66222813 Thomas Thrainer
    for disk_template in [constants.DT_FILE, constants.DT_SHARED_FILE]:
1102 66222813 Thomas Thrainer
      disk_info = [{
1103 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 80 * 1024,
1104 66222813 Thomas Thrainer
        constants.IDISK_MODE: constants.DISK_RDONLY,
1105 66222813 Thomas Thrainer
        }, {
1106 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 4096,
1107 66222813 Thomas Thrainer
        constants.IDISK_MODE: constants.DISK_RDWR,
1108 66222813 Thomas Thrainer
        }, {
1109 66222813 Thomas Thrainer
        constants.IDISK_SIZE: 6 * 1024,
1110 66222813 Thomas Thrainer
        constants.IDISK_MODE: constants.DISK_RDWR,
1111 66222813 Thomas Thrainer
        }]
1112 66222813 Thomas Thrainer
1113 66222813 Thomas Thrainer
      self.cluster.enabled_disk_templates = [disk_template]
1114 66222813 Thomas Thrainer
      result = self._TestTrivialDisk(
1115 0c5f1b13 Thomas Thrainer
        disk_template, disk_info, 2, disk_template,
1116 66222813 Thomas Thrainer
        file_storage_dir="/tmp", file_driver=constants.FD_BLKTAP)
1117 66222813 Thomas Thrainer
1118 66222813 Thomas Thrainer
      self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1119 66222813 Thomas Thrainer
        (constants.FD_BLKTAP, "/tmp/disk2"),
1120 66222813 Thomas Thrainer
        (constants.FD_BLKTAP, "/tmp/disk3"),
1121 66222813 Thomas Thrainer
        (constants.FD_BLKTAP, "/tmp/disk4"),
1122 66222813 Thomas Thrainer
        ])
1123 66222813 Thomas Thrainer
1124 66222813 Thomas Thrainer
  def testBlock(self):
1125 66222813 Thomas Thrainer
    disk_info = [{
1126 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 8 * 1024,
1127 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDWR,
1128 66222813 Thomas Thrainer
      constants.IDISK_ADOPT: "/tmp/some/block/dev",
1129 66222813 Thomas Thrainer
      }]
1130 66222813 Thomas Thrainer
1131 66222813 Thomas Thrainer
    result = self._TestTrivialDisk(constants.DT_BLOCK, disk_info, 10,
1132 0c5f1b13 Thomas Thrainer
                                   constants.DT_BLOCK)
1133 66222813 Thomas Thrainer
1134 66222813 Thomas Thrainer
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1135 66222813 Thomas Thrainer
      (constants.BLOCKDEV_DRIVER_MANUAL, "/tmp/some/block/dev"),
1136 66222813 Thomas Thrainer
      ])
1137 66222813 Thomas Thrainer
1138 66222813 Thomas Thrainer
  def testRbd(self):
1139 66222813 Thomas Thrainer
    disk_info = [{
1140 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 8 * 1024,
1141 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDONLY,
1142 66222813 Thomas Thrainer
      }, {
1143 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 100 * 1024,
1144 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDWR,
1145 66222813 Thomas Thrainer
      }]
1146 66222813 Thomas Thrainer
1147 66222813 Thomas Thrainer
    result = self._TestTrivialDisk(constants.DT_RBD, disk_info, 0,
1148 0c5f1b13 Thomas Thrainer
                                   constants.DT_RBD)
1149 66222813 Thomas Thrainer
1150 66222813 Thomas Thrainer
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1151 66222813 Thomas Thrainer
      ("rbd", "ec1-uq0.rbd.disk0"),
1152 66222813 Thomas Thrainer
      ("rbd", "ec1-uq1.rbd.disk1"),
1153 66222813 Thomas Thrainer
      ])
1154 66222813 Thomas Thrainer
1155 66222813 Thomas Thrainer
  def testDrbd8(self):
1156 66222813 Thomas Thrainer
    gdt = instance.GenerateDiskTemplate
1157 0c5f1b13 Thomas Thrainer
    drbd8_defaults = constants.DISK_LD_DEFAULTS[constants.DT_DRBD8]
1158 66222813 Thomas Thrainer
    drbd8_default_metavg = drbd8_defaults[constants.LDP_DEFAULT_METAVG]
1159 66222813 Thomas Thrainer
1160 66222813 Thomas Thrainer
    disk_info = [{
1161 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 1024,
1162 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDWR,
1163 66222813 Thomas Thrainer
      }, {
1164 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 100 * 1024,
1165 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDONLY,
1166 66222813 Thomas Thrainer
      constants.IDISK_METAVG: "metavg",
1167 66222813 Thomas Thrainer
      }, {
1168 66222813 Thomas Thrainer
      constants.IDISK_SIZE: 4096,
1169 66222813 Thomas Thrainer
      constants.IDISK_MODE: constants.DISK_RDWR,
1170 66222813 Thomas Thrainer
      constants.IDISK_VG: "vgxyz",
1171 66222813 Thomas Thrainer
      },
1172 66222813 Thomas Thrainer
      ]
1173 66222813 Thomas Thrainer
1174 66222813 Thomas Thrainer
    exp_logical_ids = [
1175 66222813 Thomas Thrainer
      [
1176 66222813 Thomas Thrainer
        (self.lu.cfg.GetVGName(), "ec1-uq0.disk0_data"),
1177 66222813 Thomas Thrainer
        (drbd8_default_metavg, "ec1-uq0.disk0_meta"),
1178 66222813 Thomas Thrainer
      ], [
1179 66222813 Thomas Thrainer
        (self.lu.cfg.GetVGName(), "ec1-uq1.disk1_data"),
1180 66222813 Thomas Thrainer
        ("metavg", "ec1-uq1.disk1_meta"),
1181 66222813 Thomas Thrainer
      ], [
1182 66222813 Thomas Thrainer
        ("vgxyz", "ec1-uq2.disk2_data"),
1183 66222813 Thomas Thrainer
        (drbd8_default_metavg, "ec1-uq2.disk2_meta"),
1184 66222813 Thomas Thrainer
      ]]
1185 66222813 Thomas Thrainer
1186 66222813 Thomas Thrainer
    assert len(exp_logical_ids) == len(disk_info)
1187 66222813 Thomas Thrainer
1188 66222813 Thomas Thrainer
    map(lambda params: utils.ForceDictType(params,
1189 66222813 Thomas Thrainer
                                           constants.IDISK_PARAMS_TYPES),
1190 66222813 Thomas Thrainer
        disk_info)
1191 66222813 Thomas Thrainer
1192 66222813 Thomas Thrainer
    # Check if empty list of secondaries is rejected
1193 66222813 Thomas Thrainer
    self.assertRaises(errors.ProgrammerError, gdt, self.lu, constants.DT_DRBD8,
1194 66222813 Thomas Thrainer
                      "inst827.example.com", "node1334.example.com", [],
1195 66222813 Thomas Thrainer
                      disk_info, NotImplemented, NotImplemented, 0,
1196 66222813 Thomas Thrainer
                      self.lu.LogInfo, self.GetDiskParams())
1197 66222813 Thomas Thrainer
1198 66222813 Thomas Thrainer
    result = gdt(self.lu, constants.DT_DRBD8, "inst827.example.com",
1199 66222813 Thomas Thrainer
                 "node1334.example.com", ["node12272.example.com"],
1200 66222813 Thomas Thrainer
                 disk_info, NotImplemented, NotImplemented, 0, self.lu.LogInfo,
1201 66222813 Thomas Thrainer
                 self.GetDiskParams())
1202 66222813 Thomas Thrainer
1203 66222813 Thomas Thrainer
    for (idx, disk) in enumerate(result):
1204 66222813 Thomas Thrainer
      self.assertTrue(isinstance(disk, objects.Disk))
1205 0c5f1b13 Thomas Thrainer
      self.assertEqual(disk.dev_type, constants.DT_DRBD8)
1206 66222813 Thomas Thrainer
      self.assertEqual(disk.size, disk_info[idx][constants.IDISK_SIZE])
1207 66222813 Thomas Thrainer
      self.assertEqual(disk.mode, disk_info[idx][constants.IDISK_MODE])
1208 66222813 Thomas Thrainer
1209 66222813 Thomas Thrainer
      for child in disk.children:
1210 66222813 Thomas Thrainer
        self.assertTrue(isinstance(disk, objects.Disk))
1211 0c5f1b13 Thomas Thrainer
        self.assertEqual(child.dev_type, constants.DT_PLAIN)
1212 66222813 Thomas Thrainer
        self.assertTrue(child.children is None)
1213 66222813 Thomas Thrainer
1214 66222813 Thomas Thrainer
      self.assertEqual(map(operator.attrgetter("logical_id"), disk.children),
1215 66222813 Thomas Thrainer
                       exp_logical_ids[idx])
1216 66222813 Thomas Thrainer
1217 66222813 Thomas Thrainer
      self.assertEqual(len(disk.children), 2)
1218 66222813 Thomas Thrainer
      self.assertEqual(disk.children[0].size, disk.size)
1219 66222813 Thomas Thrainer
      self.assertEqual(disk.children[1].size, constants.DRBD_META_SIZE)
1220 66222813 Thomas Thrainer
1221 66222813 Thomas Thrainer
    self._CheckIvNames(result, 0, len(disk_info))
1222 66222813 Thomas Thrainer
    instance._UpdateIvNames(0, result)
1223 66222813 Thomas Thrainer
    self._CheckIvNames(result, 0, len(disk_info))
1224 66222813 Thomas Thrainer
1225 66222813 Thomas Thrainer
    self.assertEqual(map(operator.attrgetter("logical_id"), result), [
1226 66222813 Thomas Thrainer
      ("node1334.example.com", "node12272.example.com",
1227 66222813 Thomas Thrainer
       constants.FIRST_DRBD_PORT, 20, 21, "ec1-secret0"),
1228 66222813 Thomas Thrainer
      ("node1334.example.com", "node12272.example.com",
1229 66222813 Thomas Thrainer
       constants.FIRST_DRBD_PORT + 1, 22, 23, "ec1-secret1"),
1230 66222813 Thomas Thrainer
      ("node1334.example.com", "node12272.example.com",
1231 66222813 Thomas Thrainer
       constants.FIRST_DRBD_PORT + 2, 24, 25, "ec1-secret2"),
1232 66222813 Thomas Thrainer
      ])
1233 66222813 Thomas Thrainer
1234 66222813 Thomas Thrainer
1235 66222813 Thomas Thrainer
class _DiskPauseTracker:
1236 66222813 Thomas Thrainer
  def __init__(self):
1237 66222813 Thomas Thrainer
    self.history = []
1238 66222813 Thomas Thrainer
1239 66222813 Thomas Thrainer
  def __call__(self, (disks, instance), pause):
1240 66222813 Thomas Thrainer
    assert not (set(disks) - set(instance.disks))
1241 66222813 Thomas Thrainer
1242 66222813 Thomas Thrainer
    self.history.extend((i.logical_id, i.size, pause)
1243 66222813 Thomas Thrainer
                        for i in disks)
1244 66222813 Thomas Thrainer
1245 66222813 Thomas Thrainer
    return (True, [True] * len(disks))
1246 66222813 Thomas Thrainer
1247 66222813 Thomas Thrainer
1248 66222813 Thomas Thrainer
class _ConfigForDiskWipe:
1249 66222813 Thomas Thrainer
  def __init__(self, exp_node_uuid):
1250 66222813 Thomas Thrainer
    self._exp_node_uuid = exp_node_uuid
1251 66222813 Thomas Thrainer
1252 66222813 Thomas Thrainer
  def GetNodeName(self, node_uuid):
1253 66222813 Thomas Thrainer
    assert node_uuid == self._exp_node_uuid
1254 66222813 Thomas Thrainer
    return "name.of.expected.node"
1255 66222813 Thomas Thrainer
1256 66222813 Thomas Thrainer
1257 66222813 Thomas Thrainer
class _RpcForDiskWipe:
1258 66222813 Thomas Thrainer
  def __init__(self, exp_node, pause_cb, wipe_cb):
1259 66222813 Thomas Thrainer
    self._exp_node = exp_node
1260 66222813 Thomas Thrainer
    self._pause_cb = pause_cb
1261 66222813 Thomas Thrainer
    self._wipe_cb = wipe_cb
1262 66222813 Thomas Thrainer
1263 66222813 Thomas Thrainer
  def call_blockdev_pause_resume_sync(self, node, disks, pause):
1264 66222813 Thomas Thrainer
    assert node == self._exp_node
1265 66222813 Thomas Thrainer
    return rpc.RpcResult(data=self._pause_cb(disks, pause))
1266 66222813 Thomas Thrainer
1267 66222813 Thomas Thrainer
  def call_blockdev_wipe(self, node, bdev, offset, size):
1268 66222813 Thomas Thrainer
    assert node == self._exp_node
1269 66222813 Thomas Thrainer
    return rpc.RpcResult(data=self._wipe_cb(bdev, offset, size))
1270 66222813 Thomas Thrainer
1271 66222813 Thomas Thrainer
1272 66222813 Thomas Thrainer
class _DiskWipeProgressTracker:
1273 66222813 Thomas Thrainer
  def __init__(self, start_offset):
1274 66222813 Thomas Thrainer
    self._start_offset = start_offset
1275 66222813 Thomas Thrainer
    self.progress = {}
1276 66222813 Thomas Thrainer
1277 66222813 Thomas Thrainer
  def __call__(self, (disk, _), offset, size):
1278 66222813 Thomas Thrainer
    assert isinstance(offset, (long, int))
1279 66222813 Thomas Thrainer
    assert isinstance(size, (long, int))
1280 66222813 Thomas Thrainer
1281 66222813 Thomas Thrainer
    max_chunk_size = (disk.size / 100.0 * constants.MIN_WIPE_CHUNK_PERCENT)
1282 66222813 Thomas Thrainer
1283 66222813 Thomas Thrainer
    assert offset >= self._start_offset
1284 66222813 Thomas Thrainer
    assert (offset + size) <= disk.size
1285 66222813 Thomas Thrainer
1286 66222813 Thomas Thrainer
    assert size > 0
1287 66222813 Thomas Thrainer
    assert size <= constants.MAX_WIPE_CHUNK
1288 66222813 Thomas Thrainer
    assert size <= max_chunk_size
1289 66222813 Thomas Thrainer
1290 66222813 Thomas Thrainer
    assert offset == self._start_offset or disk.logical_id in self.progress
1291 66222813 Thomas Thrainer
1292 66222813 Thomas Thrainer
    # Keep track of progress
1293 66222813 Thomas Thrainer
    cur_progress = self.progress.setdefault(disk.logical_id, self._start_offset)
1294 66222813 Thomas Thrainer
1295 66222813 Thomas Thrainer
    assert cur_progress == offset
1296 66222813 Thomas Thrainer
1297 66222813 Thomas Thrainer
    # Record progress
1298 66222813 Thomas Thrainer
    self.progress[disk.logical_id] += size
1299 66222813 Thomas Thrainer
1300 66222813 Thomas Thrainer
    return (True, None)
1301 66222813 Thomas Thrainer
1302 66222813 Thomas Thrainer
1303 66222813 Thomas Thrainer
class TestWipeDisks(unittest.TestCase):
1304 66222813 Thomas Thrainer
  def _FailingPauseCb(self, (disks, _), pause):
1305 66222813 Thomas Thrainer
    self.assertEqual(len(disks), 3)
1306 66222813 Thomas Thrainer
    self.assertTrue(pause)
1307 66222813 Thomas Thrainer
    # Simulate an RPC error
1308 66222813 Thomas Thrainer
    return (False, "error")
1309 66222813 Thomas Thrainer
1310 66222813 Thomas Thrainer
  def testPauseFailure(self):
1311 66222813 Thomas Thrainer
    node_name = "node1372.example.com"
1312 66222813 Thomas Thrainer
1313 66222813 Thomas Thrainer
    lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, self._FailingPauseCb,
1314 66222813 Thomas Thrainer
                                     NotImplemented),
1315 66222813 Thomas Thrainer
                 cfg=_ConfigForDiskWipe(node_name))
1316 66222813 Thomas Thrainer
1317 66222813 Thomas Thrainer
    disks = [
1318 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN),
1319 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN),
1320 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN),
1321 66222813 Thomas Thrainer
      ]
1322 66222813 Thomas Thrainer
1323 66222813 Thomas Thrainer
    inst = objects.Instance(name="inst21201",
1324 66222813 Thomas Thrainer
                            primary_node=node_name,
1325 66222813 Thomas Thrainer
                            disk_template=constants.DT_PLAIN,
1326 66222813 Thomas Thrainer
                            disks=disks)
1327 66222813 Thomas Thrainer
1328 66222813 Thomas Thrainer
    self.assertRaises(errors.OpExecError, instance.WipeDisks, lu, inst)
1329 66222813 Thomas Thrainer
1330 66222813 Thomas Thrainer
  def _FailingWipeCb(self, (disk, _), offset, size):
1331 66222813 Thomas Thrainer
    # This should only ever be called for the first disk
1332 66222813 Thomas Thrainer
    self.assertEqual(disk.logical_id, "disk0")
1333 66222813 Thomas Thrainer
    return (False, None)
1334 66222813 Thomas Thrainer
1335 66222813 Thomas Thrainer
  def testFailingWipe(self):
1336 66222813 Thomas Thrainer
    node_uuid = "node13445-uuid"
1337 66222813 Thomas Thrainer
    pt = _DiskPauseTracker()
1338 66222813 Thomas Thrainer
1339 66222813 Thomas Thrainer
    lu = _FakeLU(rpc=_RpcForDiskWipe(node_uuid, pt, self._FailingWipeCb),
1340 66222813 Thomas Thrainer
                 cfg=_ConfigForDiskWipe(node_uuid))
1341 66222813 Thomas Thrainer
1342 66222813 Thomas Thrainer
    disks = [
1343 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk0",
1344 66222813 Thomas Thrainer
                   size=100 * 1024),
1345 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk1",
1346 66222813 Thomas Thrainer
                   size=500 * 1024),
1347 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk2", size=256),
1348 66222813 Thomas Thrainer
      ]
1349 66222813 Thomas Thrainer
1350 66222813 Thomas Thrainer
    inst = objects.Instance(name="inst562",
1351 66222813 Thomas Thrainer
                            primary_node=node_uuid,
1352 66222813 Thomas Thrainer
                            disk_template=constants.DT_PLAIN,
1353 66222813 Thomas Thrainer
                            disks=disks)
1354 66222813 Thomas Thrainer
1355 66222813 Thomas Thrainer
    try:
1356 66222813 Thomas Thrainer
      instance.WipeDisks(lu, inst)
1357 66222813 Thomas Thrainer
    except errors.OpExecError, err:
1358 66222813 Thomas Thrainer
      self.assertTrue(str(err), "Could not wipe disk 0 at offset 0 ")
1359 66222813 Thomas Thrainer
    else:
1360 66222813 Thomas Thrainer
      self.fail("Did not raise exception")
1361 66222813 Thomas Thrainer
1362 66222813 Thomas Thrainer
    # Check if all disks were paused and resumed
1363 66222813 Thomas Thrainer
    self.assertEqual(pt.history, [
1364 66222813 Thomas Thrainer
      ("disk0", 100 * 1024, True),
1365 66222813 Thomas Thrainer
      ("disk1", 500 * 1024, True),
1366 66222813 Thomas Thrainer
      ("disk2", 256, True),
1367 66222813 Thomas Thrainer
      ("disk0", 100 * 1024, False),
1368 66222813 Thomas Thrainer
      ("disk1", 500 * 1024, False),
1369 66222813 Thomas Thrainer
      ("disk2", 256, False),
1370 66222813 Thomas Thrainer
      ])
1371 66222813 Thomas Thrainer
1372 66222813 Thomas Thrainer
  def _PrepareWipeTest(self, start_offset, disks):
1373 66222813 Thomas Thrainer
    node_name = "node-with-offset%s.example.com" % start_offset
1374 66222813 Thomas Thrainer
    pauset = _DiskPauseTracker()
1375 66222813 Thomas Thrainer
    progresst = _DiskWipeProgressTracker(start_offset)
1376 66222813 Thomas Thrainer
1377 66222813 Thomas Thrainer
    lu = _FakeLU(rpc=_RpcForDiskWipe(node_name, pauset, progresst),
1378 66222813 Thomas Thrainer
                 cfg=_ConfigForDiskWipe(node_name))
1379 66222813 Thomas Thrainer
1380 66222813 Thomas Thrainer
    instance = objects.Instance(name="inst3560",
1381 66222813 Thomas Thrainer
                                primary_node=node_name,
1382 66222813 Thomas Thrainer
                                disk_template=constants.DT_PLAIN,
1383 66222813 Thomas Thrainer
                                disks=disks)
1384 66222813 Thomas Thrainer
1385 66222813 Thomas Thrainer
    return (lu, instance, pauset, progresst)
1386 66222813 Thomas Thrainer
1387 66222813 Thomas Thrainer
  def testNormalWipe(self):
1388 66222813 Thomas Thrainer
    disks = [
1389 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk0", size=1024),
1390 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk1",
1391 66222813 Thomas Thrainer
                   size=500 * 1024),
1392 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk2", size=128),
1393 0c5f1b13 Thomas Thrainer
      objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk3",
1394 66222813 Thomas Thrainer
                   size=constants.MAX_WIPE_CHUNK),
1395 66222813 Thomas Thrainer
      ]
1396 66222813 Thomas Thrainer
1397 66222813 Thomas Thrainer
    (lu, inst, pauset, progresst) = self._PrepareWipeTest(0, disks)
1398 66222813 Thomas Thrainer
1399 66222813 Thomas Thrainer
    instance.WipeDisks(lu, inst)
1400 66222813 Thomas Thrainer
1401 66222813 Thomas Thrainer
    self.assertEqual(pauset.history, [
1402 66222813 Thomas Thrainer
      ("disk0", 1024, True),
1403 66222813 Thomas Thrainer
      ("disk1", 500 * 1024, True),
1404 66222813 Thomas Thrainer
      ("disk2", 128, True),
1405 66222813 Thomas Thrainer
      ("disk3", constants.MAX_WIPE_CHUNK, True),
1406 66222813 Thomas Thrainer
      ("disk0", 1024, False),
1407 66222813 Thomas Thrainer
      ("disk1", 500 * 1024, False),
1408 66222813 Thomas Thrainer
      ("disk2", 128, False),
1409 66222813 Thomas Thrainer
      ("disk3", constants.MAX_WIPE_CHUNK, False),
1410 66222813 Thomas Thrainer
      ])
1411 66222813 Thomas Thrainer
1412 66222813 Thomas Thrainer
    # Ensure the complete disk has been wiped
1413 66222813 Thomas Thrainer
    self.assertEqual(progresst.progress,
1414 66222813 Thomas Thrainer
                     dict((i.logical_id, i.size) for i in disks))
1415 66222813 Thomas Thrainer
1416 66222813 Thomas Thrainer
  def testWipeWithStartOffset(self):
1417 66222813 Thomas Thrainer
    for start_offset in [0, 280, 8895, 1563204]:
1418 66222813 Thomas Thrainer
      disks = [
1419 0c5f1b13 Thomas Thrainer
        objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk0",
1420 66222813 Thomas Thrainer
                     size=128),
1421 0c5f1b13 Thomas Thrainer
        objects.Disk(dev_type=constants.DT_PLAIN, logical_id="disk1",
1422 66222813 Thomas Thrainer
                     size=start_offset + (100 * 1024)),
1423 66222813 Thomas Thrainer
        ]
1424 66222813 Thomas Thrainer
1425 66222813 Thomas Thrainer
      (lu, inst, pauset, progresst) = \
1426 66222813 Thomas Thrainer
        self._PrepareWipeTest(start_offset, disks)
1427 66222813 Thomas Thrainer
1428 66222813 Thomas Thrainer
      # Test start offset with only one disk
1429 66222813 Thomas Thrainer
      instance.WipeDisks(lu, inst,
1430 66222813 Thomas Thrainer
                         disks=[(1, disks[1], start_offset)])
1431 66222813 Thomas Thrainer
1432 66222813 Thomas Thrainer
      # Only the second disk may have been paused and wiped
1433 66222813 Thomas Thrainer
      self.assertEqual(pauset.history, [
1434 66222813 Thomas Thrainer
        ("disk1", start_offset + (100 * 1024), True),
1435 66222813 Thomas Thrainer
        ("disk1", start_offset + (100 * 1024), False),
1436 66222813 Thomas Thrainer
        ])
1437 66222813 Thomas Thrainer
      self.assertEqual(progresst.progress, {
1438 66222813 Thomas Thrainer
        "disk1": disks[1].size,
1439 66222813 Thomas Thrainer
        })
1440 66222813 Thomas Thrainer
1441 66222813 Thomas Thrainer
1442 66222813 Thomas Thrainer
class TestCheckOpportunisticLocking(unittest.TestCase):
1443 66222813 Thomas Thrainer
  class OpTest(opcodes.OpCode):
1444 66222813 Thomas Thrainer
    OP_PARAMS = [
1445 66222813 Thomas Thrainer
      ("opportunistic_locking", False, ht.TBool, None),
1446 66222813 Thomas Thrainer
      ("iallocator", None, ht.TMaybe(ht.TNonEmptyString), "")
1447 66222813 Thomas Thrainer
      ]
1448 66222813 Thomas Thrainer
1449 66222813 Thomas Thrainer
  @classmethod
1450 66222813 Thomas Thrainer
  def _MakeOp(cls, **kwargs):
1451 66222813 Thomas Thrainer
    op = cls.OpTest(**kwargs)
1452 66222813 Thomas Thrainer
    op.Validate(True)
1453 66222813 Thomas Thrainer
    return op
1454 66222813 Thomas Thrainer
1455 66222813 Thomas Thrainer
  def testMissingAttributes(self):
1456 66222813 Thomas Thrainer
    self.assertRaises(AttributeError, instance._CheckOpportunisticLocking,
1457 66222813 Thomas Thrainer
                      object())
1458 66222813 Thomas Thrainer
1459 66222813 Thomas Thrainer
  def testDefaults(self):
1460 66222813 Thomas Thrainer
    op = self._MakeOp()
1461 66222813 Thomas Thrainer
    instance._CheckOpportunisticLocking(op)
1462 66222813 Thomas Thrainer
1463 66222813 Thomas Thrainer
  def test(self):
1464 66222813 Thomas Thrainer
    for iallocator in [None, "something", "other"]:
1465 66222813 Thomas Thrainer
      for opplock in [False, True]:
1466 66222813 Thomas Thrainer
        op = self._MakeOp(iallocator=iallocator,
1467 66222813 Thomas Thrainer
                          opportunistic_locking=opplock)
1468 66222813 Thomas Thrainer
        if opplock and not iallocator:
1469 66222813 Thomas Thrainer
          self.assertRaises(errors.OpPrereqError,
1470 66222813 Thomas Thrainer
                            instance._CheckOpportunisticLocking, op)
1471 66222813 Thomas Thrainer
        else:
1472 66222813 Thomas Thrainer
          instance._CheckOpportunisticLocking(op)
1473 66222813 Thomas Thrainer
1474 66222813 Thomas Thrainer
1475 e066018b Thomas Thrainer
class TestLUInstanceRemove(CmdlibTestCase):
1476 e066018b Thomas Thrainer
  def testRemoveMissingInstance(self):
1477 e066018b Thomas Thrainer
    op = opcodes.OpInstanceRemove(instance_name="missing.inst")
1478 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Instance 'missing.inst' not known")
1479 e066018b Thomas Thrainer
1480 e066018b Thomas Thrainer
  def testRemoveInst(self):
1481 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance(disks=[])
1482 e066018b Thomas Thrainer
    op = opcodes.OpInstanceRemove(instance_name=inst.name)
1483 e066018b Thomas Thrainer
    self.ExecOpCode(op)
1484 e066018b Thomas Thrainer
1485 e066018b Thomas Thrainer
1486 e066018b Thomas Thrainer
class TestLUInstanceMove(CmdlibTestCase):
1487 e066018b Thomas Thrainer
  def setUp(self):
1488 e066018b Thomas Thrainer
    super(TestLUInstanceMove, self).setUp()
1489 e066018b Thomas Thrainer
1490 e066018b Thomas Thrainer
    self.node = self.cfg.AddNewNode()
1491 e066018b Thomas Thrainer
1492 e066018b Thomas Thrainer
    self.rpc.call_blockdev_assemble.return_value = \
1493 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1494 e066018b Thomas Thrainer
        .CreateSuccessfulNodeResult(self.node, "/dev/mocked_path")
1495 e066018b Thomas Thrainer
    self.rpc.call_blockdev_export.return_value = \
1496 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1497 e066018b Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, "")
1498 e066018b Thomas Thrainer
    self.rpc.call_blockdev_remove.return_value = \
1499 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1500 e066018b Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, "")
1501 e066018b Thomas Thrainer
1502 e066018b Thomas Thrainer
  def testMissingInstance(self):
1503 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name="missing.inst",
1504 e066018b Thomas Thrainer
                                target_node=self.node.name)
1505 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Instance 'missing.inst' not known")
1506 e066018b Thomas Thrainer
1507 e066018b Thomas Thrainer
  def testUncopyableDiskTemplate(self):
1508 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance(disk_template=constants.DT_SHARED_FILE)
1509 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1510 e066018b Thomas Thrainer
                                target_node=self.node.name)
1511 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1512 e066018b Thomas Thrainer
      op, "Disk template sharedfile not suitable for copying")
1513 e066018b Thomas Thrainer
1514 e066018b Thomas Thrainer
  def testAlreadyOnTargetNode(self):
1515 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance()
1516 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1517 e066018b Thomas Thrainer
                                target_node=self.master.name)
1518 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1519 e066018b Thomas Thrainer
      op, "Instance .* is already on the node .*")
1520 e066018b Thomas Thrainer
1521 e066018b Thomas Thrainer
  def testMoveStoppedInstance(self):
1522 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance()
1523 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1524 e066018b Thomas Thrainer
                                target_node=self.node.name)
1525 e066018b Thomas Thrainer
    self.ExecOpCode(op)
1526 e066018b Thomas Thrainer
1527 e066018b Thomas Thrainer
  def testMoveRunningInstance(self):
1528 e066018b Thomas Thrainer
    self.rpc.call_node_info.return_value = \
1529 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1530 e066018b Thomas Thrainer
        .AddSuccessfulNode(self.node,
1531 e066018b Thomas Thrainer
                           (NotImplemented, NotImplemented,
1532 e066018b Thomas Thrainer
                            ({"memory_free": 10000}, ))) \
1533 e066018b Thomas Thrainer
        .Build()
1534 e066018b Thomas Thrainer
    self.rpc.call_instance_start.return_value = \
1535 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1536 e066018b Thomas Thrainer
        .CreateSuccessfulNodeResult(self.node, "")
1537 e066018b Thomas Thrainer
1538 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance(admin_state=constants.ADMINST_UP)
1539 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1540 e066018b Thomas Thrainer
                                target_node=self.node.name)
1541 e066018b Thomas Thrainer
    self.ExecOpCode(op)
1542 e066018b Thomas Thrainer
1543 e066018b Thomas Thrainer
  def testMoveFailingStart(self):
1544 e066018b Thomas Thrainer
    self.rpc.call_node_info.return_value = \
1545 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1546 e066018b Thomas Thrainer
        .AddSuccessfulNode(self.node,
1547 e066018b Thomas Thrainer
                           (NotImplemented, NotImplemented,
1548 e066018b Thomas Thrainer
                            ({"memory_free": 10000}, ))) \
1549 e066018b Thomas Thrainer
        .Build()
1550 e066018b Thomas Thrainer
    self.rpc.call_instance_start.return_value = \
1551 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1552 e066018b Thomas Thrainer
        .CreateFailedNodeResult(self.node)
1553 e066018b Thomas Thrainer
1554 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance(admin_state=constants.ADMINST_UP)
1555 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1556 e066018b Thomas Thrainer
                                target_node=self.node.name)
1557 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpExecError(
1558 e066018b Thomas Thrainer
      op, "Could not start instance .* on node .*")
1559 e066018b Thomas Thrainer
1560 e066018b Thomas Thrainer
  def testMoveFailingBlockdevAssemble(self):
1561 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance()
1562 e066018b Thomas Thrainer
    self.rpc.call_blockdev_assemble.return_value = \
1563 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1564 e066018b Thomas Thrainer
        .CreateFailedNodeResult(self.node)
1565 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1566 e066018b Thomas Thrainer
                                target_node=self.node.name)
1567 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpExecError(op, "Errors during disk copy")
1568 e066018b Thomas Thrainer
1569 e066018b Thomas Thrainer
  def testMoveFailingBlockdevExport(self):
1570 e066018b Thomas Thrainer
    inst = self.cfg.AddNewInstance()
1571 e066018b Thomas Thrainer
    self.rpc.call_blockdev_export.return_value = \
1572 e066018b Thomas Thrainer
      self.RpcResultsBuilder() \
1573 e066018b Thomas Thrainer
        .CreateFailedNodeResult(self.node)
1574 e066018b Thomas Thrainer
    op = opcodes.OpInstanceMove(instance_name=inst.name,
1575 e066018b Thomas Thrainer
                                target_node=self.node.name)
1576 e066018b Thomas Thrainer
    self.ExecOpCodeExpectOpExecError(op, "Errors during disk copy")
1577 e066018b Thomas Thrainer
1578 e066018b Thomas Thrainer
1579 bf2a3eba Thomas Thrainer
class TestLUInstanceRename(CmdlibTestCase):
1580 bf2a3eba Thomas Thrainer
  def setUp(self):
1581 bf2a3eba Thomas Thrainer
    super(TestLUInstanceRename, self).setUp()
1582 bf2a3eba Thomas Thrainer
1583 bf2a3eba Thomas Thrainer
    self.inst = self.cfg.AddNewInstance()
1584 bf2a3eba Thomas Thrainer
1585 bf2a3eba Thomas Thrainer
    self.op = opcodes.OpInstanceRename(instance_name=self.inst.name,
1586 bf2a3eba Thomas Thrainer
                                       new_name="new_name.example.com")
1587 bf2a3eba Thomas Thrainer
1588 bf2a3eba Thomas Thrainer
  def testIpCheckWithoutNameCheck(self):
1589 bf2a3eba Thomas Thrainer
    op = self.CopyOpCode(self.op,
1590 bf2a3eba Thomas Thrainer
                         ip_check=True,
1591 bf2a3eba Thomas Thrainer
                         name_check=False)
1592 bf2a3eba Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1593 bf2a3eba Thomas Thrainer
      op, "IP address check requires a name check")
1594 bf2a3eba Thomas Thrainer
1595 bf2a3eba Thomas Thrainer
  def testIpAlreadyInUse(self):
1596 bf2a3eba Thomas Thrainer
    self.netutils_mod.TcpPing.return_value = True
1597 bf2a3eba Thomas Thrainer
    op = self.CopyOpCode(self.op)
1598 bf2a3eba Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1599 bf2a3eba Thomas Thrainer
      op, "IP .* of instance .* already in use")
1600 bf2a3eba Thomas Thrainer
1601 bf2a3eba Thomas Thrainer
  def testExistingInstanceName(self):
1602 bf2a3eba Thomas Thrainer
    self.cfg.AddNewInstance(name="new_name.example.com")
1603 bf2a3eba Thomas Thrainer
    op = self.CopyOpCode(self.op)
1604 bf2a3eba Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1605 bf2a3eba Thomas Thrainer
      op, "Instance .* is already in the cluster")
1606 bf2a3eba Thomas Thrainer
1607 bf2a3eba Thomas Thrainer
  def testFileInstance(self):
1608 bf2a3eba Thomas Thrainer
    self.rpc.call_blockdev_assemble.return_value = \
1609 bf2a3eba Thomas Thrainer
      self.RpcResultsBuilder() \
1610 bf2a3eba Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, None)
1611 bf2a3eba Thomas Thrainer
    self.rpc.call_blockdev_shutdown.return_value = \
1612 bf2a3eba Thomas Thrainer
      self.RpcResultsBuilder() \
1613 bf2a3eba Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, None)
1614 bf2a3eba Thomas Thrainer
1615 bf2a3eba Thomas Thrainer
    inst = self.cfg.AddNewInstance(disk_template=constants.DT_FILE)
1616 bf2a3eba Thomas Thrainer
    op = self.CopyOpCode(self.op,
1617 bf2a3eba Thomas Thrainer
                         instance_name=inst.name)
1618 bf2a3eba Thomas Thrainer
    self.ExecOpCode(op)
1619 bf2a3eba Thomas Thrainer
1620 bf2a3eba Thomas Thrainer
1621 4a8c84f3 Thomas Thrainer
class TestLUInstanceMultiAlloc(CmdlibTestCase):
1622 4a8c84f3 Thomas Thrainer
  def setUp(self):
1623 4a8c84f3 Thomas Thrainer
    super(TestLUInstanceMultiAlloc, self).setUp()
1624 4a8c84f3 Thomas Thrainer
1625 4a8c84f3 Thomas Thrainer
    self.inst_op = opcodes.OpInstanceCreate(instance_name="inst.example.com",
1626 4a8c84f3 Thomas Thrainer
                                            disk_template=constants.DT_DRBD8,
1627 4a8c84f3 Thomas Thrainer
                                            disks=[],
1628 4a8c84f3 Thomas Thrainer
                                            nics=[],
1629 4a8c84f3 Thomas Thrainer
                                            os_type="mock_os",
1630 4a8c84f3 Thomas Thrainer
                                            hypervisor=constants.HT_XEN_HVM,
1631 4a8c84f3 Thomas Thrainer
                                            mode=constants.INSTANCE_CREATE)
1632 4a8c84f3 Thomas Thrainer
1633 4a8c84f3 Thomas Thrainer
  def testInstanceWithIAllocator(self):
1634 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op,
1635 4a8c84f3 Thomas Thrainer
                           iallocator="mock")
1636 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst])
1637 4a8c84f3 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1638 4a8c84f3 Thomas Thrainer
      op, "iallocator are not allowed to be set on instance objects")
1639 4a8c84f3 Thomas Thrainer
1640 4a8c84f3 Thomas Thrainer
  def testOnlySomeNodesGiven(self):
1641 4a8c84f3 Thomas Thrainer
    inst1 = self.CopyOpCode(self.inst_op,
1642 4a8c84f3 Thomas Thrainer
                            pnode=self.master.name)
1643 4a8c84f3 Thomas Thrainer
    inst2 = self.CopyOpCode(self.inst_op)
1644 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst1, inst2])
1645 4a8c84f3 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1646 4a8c84f3 Thomas Thrainer
      op, "There are instance objects providing pnode/snode while others"
1647 4a8c84f3 Thomas Thrainer
          " do not")
1648 4a8c84f3 Thomas Thrainer
1649 4a8c84f3 Thomas Thrainer
  def testMissingIAllocator(self):
1650 4a8c84f3 Thomas Thrainer
    self.cluster.default_iallocator = None
1651 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op)
1652 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst])
1653 4a8c84f3 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1654 4a8c84f3 Thomas Thrainer
      op, "No iallocator or nodes on the instances given and no cluster-wide"
1655 4a8c84f3 Thomas Thrainer
          " default iallocator found")
1656 4a8c84f3 Thomas Thrainer
1657 4a8c84f3 Thomas Thrainer
  def testDuplicateInstanceNames(self):
1658 4a8c84f3 Thomas Thrainer
    inst1 = self.CopyOpCode(self.inst_op)
1659 4a8c84f3 Thomas Thrainer
    inst2 = self.CopyOpCode(self.inst_op)
1660 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst1, inst2])
1661 4a8c84f3 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1662 4a8c84f3 Thomas Thrainer
      op, "There are duplicate instance names")
1663 4a8c84f3 Thomas Thrainer
1664 4a8c84f3 Thomas Thrainer
  def testWithGivenNodes(self):
1665 4a8c84f3 Thomas Thrainer
    snode = self.cfg.AddNewNode()
1666 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op,
1667 4a8c84f3 Thomas Thrainer
                           pnode=self.master.name,
1668 4a8c84f3 Thomas Thrainer
                           snode=snode.name)
1669 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst])
1670 4a8c84f3 Thomas Thrainer
    self.ExecOpCode(op)
1671 4a8c84f3 Thomas Thrainer
1672 4a8c84f3 Thomas Thrainer
  def testDryRun(self):
1673 4a8c84f3 Thomas Thrainer
    snode = self.cfg.AddNewNode()
1674 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op,
1675 4a8c84f3 Thomas Thrainer
                           pnode=self.master.name,
1676 4a8c84f3 Thomas Thrainer
                           snode=snode.name)
1677 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst],
1678 4a8c84f3 Thomas Thrainer
                                      dry_run=True)
1679 4a8c84f3 Thomas Thrainer
    self.ExecOpCode(op)
1680 4a8c84f3 Thomas Thrainer
1681 4a8c84f3 Thomas Thrainer
  def testWithIAllocator(self):
1682 4a8c84f3 Thomas Thrainer
    snode = self.cfg.AddNewNode()
1683 4a8c84f3 Thomas Thrainer
    self.iallocator_cls.return_value.result = \
1684 4a8c84f3 Thomas Thrainer
      ([("inst.example.com", [self.master.name, snode.name])], [])
1685 4a8c84f3 Thomas Thrainer
1686 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op)
1687 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst],
1688 4a8c84f3 Thomas Thrainer
                                      iallocator="mock_ialloc")
1689 4a8c84f3 Thomas Thrainer
    self.ExecOpCode(op)
1690 4a8c84f3 Thomas Thrainer
1691 4a8c84f3 Thomas Thrainer
  def testWithIAllocatorOpportunisticLocking(self):
1692 4a8c84f3 Thomas Thrainer
    snode = self.cfg.AddNewNode()
1693 4a8c84f3 Thomas Thrainer
    self.iallocator_cls.return_value.result = \
1694 4a8c84f3 Thomas Thrainer
      ([("inst.example.com", [self.master.name, snode.name])], [])
1695 4a8c84f3 Thomas Thrainer
1696 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op)
1697 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst],
1698 4a8c84f3 Thomas Thrainer
                                      iallocator="mock_ialloc",
1699 4a8c84f3 Thomas Thrainer
                                      opportunistic_locking=True)
1700 4a8c84f3 Thomas Thrainer
    self.ExecOpCode(op)
1701 4a8c84f3 Thomas Thrainer
1702 4a8c84f3 Thomas Thrainer
  def testFailingIAllocator(self):
1703 4a8c84f3 Thomas Thrainer
    self.iallocator_cls.return_value.success = False
1704 4a8c84f3 Thomas Thrainer
1705 4a8c84f3 Thomas Thrainer
    inst = self.CopyOpCode(self.inst_op)
1706 4a8c84f3 Thomas Thrainer
    op = opcodes.OpInstanceMultiAlloc(instances=[inst],
1707 4a8c84f3 Thomas Thrainer
                                      iallocator="mock_ialloc")
1708 4a8c84f3 Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1709 4a8c84f3 Thomas Thrainer
      op, "Can't compute nodes using iallocator")
1710 4a8c84f3 Thomas Thrainer
1711 4a8c84f3 Thomas Thrainer
1712 27619aac Thomas Thrainer
class TestLUInstanceSetParams(CmdlibTestCase):
1713 27619aac Thomas Thrainer
  def setUp(self):
1714 27619aac Thomas Thrainer
    super(TestLUInstanceSetParams, self).setUp()
1715 27619aac Thomas Thrainer
1716 27619aac Thomas Thrainer
    self.inst = self.cfg.AddNewInstance()
1717 27619aac Thomas Thrainer
    self.op = opcodes.OpInstanceSetParams(instance_name=self.inst.name)
1718 27619aac Thomas Thrainer
1719 27619aac Thomas Thrainer
    self.running_inst = \
1720 27619aac Thomas Thrainer
      self.cfg.AddNewInstance(admin_state=constants.ADMINST_UP)
1721 27619aac Thomas Thrainer
    self.running_op = \
1722 27619aac Thomas Thrainer
      opcodes.OpInstanceSetParams(instance_name=self.running_inst.name)
1723 27619aac Thomas Thrainer
1724 27619aac Thomas Thrainer
    self.snode = self.cfg.AddNewNode()
1725 27619aac Thomas Thrainer
1726 27619aac Thomas Thrainer
    self.mocked_storage_type = constants.ST_LVM_VG
1727 27619aac Thomas Thrainer
    self.mocked_storage_free = 10000
1728 27619aac Thomas Thrainer
    self.mocked_master_cpu_total = 16
1729 27619aac Thomas Thrainer
    self.mocked_master_memory_free = 2048
1730 27619aac Thomas Thrainer
    self.mocked_snode_cpu_total = 16
1731 27619aac Thomas Thrainer
    self.mocked_snode_memory_free = 512
1732 27619aac Thomas Thrainer
1733 27619aac Thomas Thrainer
    self.mocked_running_inst_memory = 1024
1734 27619aac Thomas Thrainer
    self.mocked_running_inst_vcpus = 8
1735 27619aac Thomas Thrainer
    self.mocked_running_inst_state = "running"
1736 27619aac Thomas Thrainer
    self.mocked_running_inst_time = 10938474
1737 27619aac Thomas Thrainer
1738 27619aac Thomas Thrainer
    bootid = "mock_bootid"
1739 27619aac Thomas Thrainer
    storage_info = [
1740 27619aac Thomas Thrainer
      {
1741 27619aac Thomas Thrainer
        "type": self.mocked_storage_type,
1742 27619aac Thomas Thrainer
        "storage_free": self.mocked_storage_free
1743 27619aac Thomas Thrainer
      }
1744 27619aac Thomas Thrainer
    ]
1745 27619aac Thomas Thrainer
    hv_info_master = {
1746 27619aac Thomas Thrainer
      "cpu_total": self.mocked_master_cpu_total,
1747 27619aac Thomas Thrainer
      "memory_free": self.mocked_master_memory_free
1748 27619aac Thomas Thrainer
    }
1749 27619aac Thomas Thrainer
    hv_info_snode = {
1750 27619aac Thomas Thrainer
      "cpu_total": self.mocked_snode_cpu_total,
1751 27619aac Thomas Thrainer
      "memory_free": self.mocked_snode_memory_free
1752 27619aac Thomas Thrainer
    }
1753 27619aac Thomas Thrainer
1754 27619aac Thomas Thrainer
    self.rpc.call_node_info.return_value = \
1755 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
1756 27619aac Thomas Thrainer
        .AddSuccessfulNode(self.master,
1757 27619aac Thomas Thrainer
                           (bootid, storage_info, (hv_info_master, ))) \
1758 27619aac Thomas Thrainer
        .AddSuccessfulNode(self.snode,
1759 27619aac Thomas Thrainer
                           (bootid, storage_info, (hv_info_snode, ))) \
1760 27619aac Thomas Thrainer
        .Build()
1761 27619aac Thomas Thrainer
1762 27619aac Thomas Thrainer
    def _InstanceInfo(_, instance, __, ___):
1763 27619aac Thomas Thrainer
      if instance == self.inst.name:
1764 27619aac Thomas Thrainer
        return self.RpcResultsBuilder() \
1765 27619aac Thomas Thrainer
          .CreateSuccessfulNodeResult(self.master, None)
1766 27619aac Thomas Thrainer
      elif instance == self.running_inst.name:
1767 27619aac Thomas Thrainer
        return self.RpcResultsBuilder() \
1768 27619aac Thomas Thrainer
          .CreateSuccessfulNodeResult(
1769 27619aac Thomas Thrainer
            self.master, {
1770 27619aac Thomas Thrainer
              "memory": self.mocked_running_inst_memory,
1771 27619aac Thomas Thrainer
              "vcpus": self.mocked_running_inst_vcpus,
1772 27619aac Thomas Thrainer
              "state": self.mocked_running_inst_state,
1773 27619aac Thomas Thrainer
              "time": self.mocked_running_inst_time
1774 27619aac Thomas Thrainer
            })
1775 27619aac Thomas Thrainer
      else:
1776 27619aac Thomas Thrainer
        raise AssertionError()
1777 27619aac Thomas Thrainer
    self.rpc.call_instance_info.side_effect = _InstanceInfo
1778 27619aac Thomas Thrainer
1779 27619aac Thomas Thrainer
    self.rpc.call_bridges_exist.return_value = \
1780 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
1781 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, True)
1782 27619aac Thomas Thrainer
1783 27619aac Thomas Thrainer
  def testNoChanges(self):
1784 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op)
1785 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "No changes submitted")
1786 27619aac Thomas Thrainer
1787 27619aac Thomas Thrainer
  def testGlobalHvparams(self):
1788 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1789 27619aac Thomas Thrainer
                         hvparams={constants.HV_MIGRATION_PORT: 1234})
1790 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1791 27619aac Thomas Thrainer
      op, "hypervisor parameters are global and cannot be customized")
1792 27619aac Thomas Thrainer
1793 27619aac Thomas Thrainer
  def testHvparams(self):
1794 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1795 27619aac Thomas Thrainer
                         hvparams={constants.HV_BOOT_ORDER: "cd"})
1796 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1797 27619aac Thomas Thrainer
1798 27619aac Thomas Thrainer
  def testDisksAndDiskTemplate(self):
1799 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1800 27619aac Thomas Thrainer
                         disk_template=constants.DT_PLAIN,
1801 27619aac Thomas Thrainer
                         disks=[[constants.DDM_ADD, -1, {}]])
1802 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1803 27619aac Thomas Thrainer
      op, "Disk template conversion and other disk changes not supported at"
1804 27619aac Thomas Thrainer
          " the same time")
1805 27619aac Thomas Thrainer
1806 27619aac Thomas Thrainer
  def testDiskTemplateToMirroredNoRemoteNode(self):
1807 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1808 27619aac Thomas Thrainer
                         disk_template=constants.DT_DRBD8)
1809 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1810 27619aac Thomas Thrainer
      op, "Changing the disk template to a mirrored one requires specifying"
1811 27619aac Thomas Thrainer
          " a secondary node")
1812 27619aac Thomas Thrainer
1813 27619aac Thomas Thrainer
  def testPrimaryNodeToOldPrimaryNode(self):
1814 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1815 27619aac Thomas Thrainer
                         pnode=self.master.name)
1816 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1817 27619aac Thomas Thrainer
1818 27619aac Thomas Thrainer
  def testPrimaryNodeChange(self):
1819 27619aac Thomas Thrainer
    node = self.cfg.AddNewNode()
1820 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1821 27619aac Thomas Thrainer
                         pnode=node.name)
1822 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1823 27619aac Thomas Thrainer
1824 27619aac Thomas Thrainer
  def testPrimaryNodeChangeRunningInstance(self):
1825 27619aac Thomas Thrainer
    node = self.cfg.AddNewNode()
1826 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.running_op,
1827 27619aac Thomas Thrainer
                         pnode=node.name)
1828 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(op, "Instance is still running")
1829 27619aac Thomas Thrainer
1830 27619aac Thomas Thrainer
  def testOsChange(self):
1831 27619aac Thomas Thrainer
    os = self.cfg.CreateOs(supported_variants=[])
1832 27619aac Thomas Thrainer
    self.rpc.call_os_get.return_value = \
1833 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
1834 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, os)
1835 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1836 27619aac Thomas Thrainer
                         os_name=os.name)
1837 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1838 27619aac Thomas Thrainer
1839 27619aac Thomas Thrainer
  def testVCpuChange(self):
1840 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1841 27619aac Thomas Thrainer
                         beparams={
1842 27619aac Thomas Thrainer
                           constants.BE_VCPUS: 4
1843 27619aac Thomas Thrainer
                         })
1844 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1845 27619aac Thomas Thrainer
1846 27619aac Thomas Thrainer
  def testWrongCpuMask(self):
1847 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1848 27619aac Thomas Thrainer
                         beparams={
1849 27619aac Thomas Thrainer
                           constants.BE_VCPUS: 4
1850 27619aac Thomas Thrainer
                         },
1851 27619aac Thomas Thrainer
                         hvparams={
1852 27619aac Thomas Thrainer
                           constants.HV_CPU_MASK: "1,2:3,4"
1853 27619aac Thomas Thrainer
                         })
1854 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1855 27619aac Thomas Thrainer
      op, "Number of vCPUs .* does not match the CPU mask .*")
1856 27619aac Thomas Thrainer
1857 27619aac Thomas Thrainer
  def testCorrectCpuMask(self):
1858 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1859 27619aac Thomas Thrainer
                         beparams={
1860 27619aac Thomas Thrainer
                           constants.BE_VCPUS: 4
1861 27619aac Thomas Thrainer
                         },
1862 27619aac Thomas Thrainer
                         hvparams={
1863 27619aac Thomas Thrainer
                           constants.HV_CPU_MASK: "1,2:3,4:all:1,4"
1864 27619aac Thomas Thrainer
                         })
1865 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1866 27619aac Thomas Thrainer
1867 27619aac Thomas Thrainer
  def testOsParams(self):
1868 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1869 27619aac Thomas Thrainer
                         osparams={
1870 27619aac Thomas Thrainer
                           self.os.supported_parameters[0]: "test_param_val"
1871 27619aac Thomas Thrainer
                         })
1872 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1873 27619aac Thomas Thrainer
1874 27619aac Thomas Thrainer
  def testIncreaseMemoryTooMuch(self):
1875 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.running_op,
1876 27619aac Thomas Thrainer
                         beparams={
1877 27619aac Thomas Thrainer
                           constants.BE_MAXMEM:
1878 27619aac Thomas Thrainer
                             self.mocked_master_memory_free * 2
1879 27619aac Thomas Thrainer
                         })
1880 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1881 27619aac Thomas Thrainer
      op, "This change will prevent the instance from starting")
1882 27619aac Thomas Thrainer
1883 27619aac Thomas Thrainer
  def testIncreaseMemory(self):
1884 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.running_op,
1885 27619aac Thomas Thrainer
                         beparams={
1886 27619aac Thomas Thrainer
                           constants.BE_MAXMEM: self.mocked_master_memory_free
1887 27619aac Thomas Thrainer
                         })
1888 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1889 27619aac Thomas Thrainer
1890 27619aac Thomas Thrainer
  def testIncreaseMemoryTooMuchForSecondary(self):
1891 27619aac Thomas Thrainer
    inst = self.cfg.AddNewInstance(admin_state=constants.ADMINST_UP,
1892 27619aac Thomas Thrainer
                                   disk_template=constants.DT_DRBD8,
1893 27619aac Thomas Thrainer
                                   secondary_node=self.snode)
1894 27619aac Thomas Thrainer
    self.rpc.call_instance_info.side_effect = [
1895 27619aac Thomas Thrainer
      self.RpcResultsBuilder()
1896 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master,
1897 27619aac Thomas Thrainer
                                    {
1898 27619aac Thomas Thrainer
                                      "memory":
1899 27619aac Thomas Thrainer
                                        self.mocked_snode_memory_free * 2,
1900 27619aac Thomas Thrainer
                                      "vcpus": self.mocked_running_inst_vcpus,
1901 27619aac Thomas Thrainer
                                      "state": self.mocked_running_inst_state,
1902 27619aac Thomas Thrainer
                                      "time": self.mocked_running_inst_time
1903 27619aac Thomas Thrainer
                                    })]
1904 27619aac Thomas Thrainer
1905 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1906 27619aac Thomas Thrainer
                         instance_name=inst.name,
1907 27619aac Thomas Thrainer
                         beparams={
1908 27619aac Thomas Thrainer
                           constants.BE_MAXMEM:
1909 27619aac Thomas Thrainer
                             self.mocked_snode_memory_free * 2,
1910 27619aac Thomas Thrainer
                           constants.BE_AUTO_BALANCE: True
1911 27619aac Thomas Thrainer
                         })
1912 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1913 27619aac Thomas Thrainer
      op, "This change will prevent the instance from failover to its"
1914 27619aac Thomas Thrainer
          " secondary node")
1915 27619aac Thomas Thrainer
1916 27619aac Thomas Thrainer
  def testInvalidRuntimeMemory(self):
1917 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.running_op,
1918 27619aac Thomas Thrainer
                         runtime_mem=self.mocked_master_memory_free * 2)
1919 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1920 27619aac Thomas Thrainer
      op, "Instance .* must have memory between .* and .* of memory")
1921 27619aac Thomas Thrainer
1922 27619aac Thomas Thrainer
  def testIncreaseRuntimeMemory(self):
1923 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.running_op,
1924 27619aac Thomas Thrainer
                         runtime_mem=self.mocked_master_memory_free,
1925 27619aac Thomas Thrainer
                         beparams={
1926 27619aac Thomas Thrainer
                           constants.BE_MAXMEM: self.mocked_master_memory_free
1927 27619aac Thomas Thrainer
                         })
1928 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1929 27619aac Thomas Thrainer
1930 27619aac Thomas Thrainer
  def testAddNicWithPoolIpNoNetwork(self):
1931 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1932 27619aac Thomas Thrainer
                         nics=[(constants.DDM_ADD, -1,
1933 27619aac Thomas Thrainer
                                {
1934 27619aac Thomas Thrainer
                                  constants.INIC_IP: constants.NIC_IP_POOL
1935 27619aac Thomas Thrainer
                                })])
1936 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1937 27619aac Thomas Thrainer
      op, "If ip=pool, parameter network cannot be none")
1938 27619aac Thomas Thrainer
1939 27619aac Thomas Thrainer
  def testAddNicWithPoolIp(self):
1940 27619aac Thomas Thrainer
    net = self.cfg.AddNewNetwork()
1941 27619aac Thomas Thrainer
    self.cfg.ConnectNetworkToGroup(net, self.group)
1942 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1943 27619aac Thomas Thrainer
                         nics=[(constants.DDM_ADD, -1,
1944 27619aac Thomas Thrainer
                                {
1945 27619aac Thomas Thrainer
                                  constants.INIC_IP: constants.NIC_IP_POOL,
1946 27619aac Thomas Thrainer
                                  constants.INIC_NETWORK: net.name
1947 27619aac Thomas Thrainer
                                })])
1948 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1949 27619aac Thomas Thrainer
1950 27619aac Thomas Thrainer
  def testAddNicWithInvalidIp(self):
1951 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1952 27619aac Thomas Thrainer
                         nics=[(constants.DDM_ADD, -1,
1953 27619aac Thomas Thrainer
                                {
1954 27619aac Thomas Thrainer
                                  constants.INIC_IP: "invalid"
1955 27619aac Thomas Thrainer
                                })])
1956 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1957 27619aac Thomas Thrainer
      op, "Invalid IP address")
1958 27619aac Thomas Thrainer
1959 27619aac Thomas Thrainer
  def testAddNic(self):
1960 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1961 27619aac Thomas Thrainer
                         nics=[(constants.DDM_ADD, -1, {})])
1962 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1963 27619aac Thomas Thrainer
1964 27619aac Thomas Thrainer
  def testAddNicWithIp(self):
1965 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1966 27619aac Thomas Thrainer
                         nics=[(constants.DDM_ADD, -1,
1967 27619aac Thomas Thrainer
                                {
1968 27619aac Thomas Thrainer
                                  constants.INIC_IP: "2.3.1.4"
1969 27619aac Thomas Thrainer
                                })])
1970 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1971 27619aac Thomas Thrainer
1972 27619aac Thomas Thrainer
  def testModifyNicRoutedWithoutIp(self):
1973 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1974 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, 0,
1975 27619aac Thomas Thrainer
                                {
1976 27619aac Thomas Thrainer
                                  constants.INIC_MODE: constants.NIC_MODE_ROUTED
1977 27619aac Thomas Thrainer
                                })])
1978 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1979 27619aac Thomas Thrainer
      op, "Cannot set the NIC IP address to None on a routed NIC")
1980 27619aac Thomas Thrainer
1981 27619aac Thomas Thrainer
  def testModifyNicSetMac(self):
1982 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1983 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, 0,
1984 27619aac Thomas Thrainer
                                {
1985 27619aac Thomas Thrainer
                                  constants.INIC_MAC: "0a:12:95:15:bf:75"
1986 27619aac Thomas Thrainer
                                })])
1987 27619aac Thomas Thrainer
    self.ExecOpCode(op)
1988 27619aac Thomas Thrainer
1989 27619aac Thomas Thrainer
  def testModifyNicWithPoolIpNoNetwork(self):
1990 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
1991 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, -1,
1992 27619aac Thomas Thrainer
                                {
1993 27619aac Thomas Thrainer
                                  constants.INIC_IP: constants.NIC_IP_POOL
1994 27619aac Thomas Thrainer
                                })])
1995 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
1996 27619aac Thomas Thrainer
      op, "ip=pool, but no network found")
1997 27619aac Thomas Thrainer
1998 27619aac Thomas Thrainer
  def testModifyNicSetNet(self):
1999 27619aac Thomas Thrainer
    old_net = self.cfg.AddNewNetwork()
2000 27619aac Thomas Thrainer
    self.cfg.ConnectNetworkToGroup(old_net, self.group)
2001 27619aac Thomas Thrainer
    inst = self.cfg.AddNewInstance(nics=[
2002 27619aac Thomas Thrainer
      self.cfg.CreateNic(network=old_net,
2003 4256f8fe Sebastian Gebhard
                         ip="198.51.100.2")])
2004 27619aac Thomas Thrainer
2005 27619aac Thomas Thrainer
    new_net = self.cfg.AddNewNetwork(mac_prefix="be")
2006 27619aac Thomas Thrainer
    self.cfg.ConnectNetworkToGroup(new_net, self.group)
2007 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2008 27619aac Thomas Thrainer
                         instance_name=inst.name,
2009 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, 0,
2010 27619aac Thomas Thrainer
                                {
2011 27619aac Thomas Thrainer
                                  constants.INIC_NETWORK: new_net.name
2012 27619aac Thomas Thrainer
                                })])
2013 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2014 27619aac Thomas Thrainer
2015 27619aac Thomas Thrainer
  def testModifyNicSetLinkWhileConnected(self):
2016 27619aac Thomas Thrainer
    old_net = self.cfg.AddNewNetwork()
2017 27619aac Thomas Thrainer
    self.cfg.ConnectNetworkToGroup(old_net, self.group)
2018 27619aac Thomas Thrainer
    inst = self.cfg.AddNewInstance(nics=[
2019 27619aac Thomas Thrainer
      self.cfg.CreateNic(network=old_net)])
2020 27619aac Thomas Thrainer
2021 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2022 27619aac Thomas Thrainer
                         instance_name=inst.name,
2023 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, 0,
2024 27619aac Thomas Thrainer
                                {
2025 27619aac Thomas Thrainer
                                  constants.INIC_LINK: "mock_link"
2026 27619aac Thomas Thrainer
                                })])
2027 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2028 27619aac Thomas Thrainer
      op, "Not allowed to change link or mode of a NIC that is connected"
2029 27619aac Thomas Thrainer
          " to a network")
2030 27619aac Thomas Thrainer
2031 27619aac Thomas Thrainer
  def testModifyNicSetNetAndIp(self):
2032 27619aac Thomas Thrainer
    net = self.cfg.AddNewNetwork(mac_prefix="be", network="123.123.123.0/24")
2033 27619aac Thomas Thrainer
    self.cfg.ConnectNetworkToGroup(net, self.group)
2034 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2035 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, 0,
2036 27619aac Thomas Thrainer
                                {
2037 27619aac Thomas Thrainer
                                  constants.INIC_NETWORK: net.name,
2038 27619aac Thomas Thrainer
                                  constants.INIC_IP: "123.123.123.1"
2039 27619aac Thomas Thrainer
                                })])
2040 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2041 27619aac Thomas Thrainer
2042 27619aac Thomas Thrainer
  def testModifyNic(self):
2043 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2044 27619aac Thomas Thrainer
                         nics=[(constants.DDM_MODIFY, 0, {})])
2045 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2046 27619aac Thomas Thrainer
2047 27619aac Thomas Thrainer
  def testRemoveLastNic(self):
2048 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2049 27619aac Thomas Thrainer
                         nics=[(constants.DDM_REMOVE, 0, {})])
2050 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2051 27619aac Thomas Thrainer
      op, "violates policy")
2052 27619aac Thomas Thrainer
2053 27619aac Thomas Thrainer
  def testRemoveNic(self):
2054 27619aac Thomas Thrainer
    inst = self.cfg.AddNewInstance(nics=[self.cfg.CreateNic(),
2055 27619aac Thomas Thrainer
                                         self.cfg.CreateNic()])
2056 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2057 27619aac Thomas Thrainer
                         instance_name=inst.name,
2058 27619aac Thomas Thrainer
                         nics=[(constants.DDM_REMOVE, 0, {})])
2059 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2060 27619aac Thomas Thrainer
2061 27619aac Thomas Thrainer
  def testSetOffline(self):
2062 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2063 27619aac Thomas Thrainer
                         offline=True)
2064 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2065 27619aac Thomas Thrainer
2066 27619aac Thomas Thrainer
  def testUnsetOffline(self):
2067 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2068 27619aac Thomas Thrainer
                         offline=False)
2069 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2070 27619aac Thomas Thrainer
2071 27619aac Thomas Thrainer
  def testAddDiskInvalidMode(self):
2072 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2073 27619aac Thomas Thrainer
                         disks=[[constants.DDM_ADD, -1,
2074 27619aac Thomas Thrainer
                                 {
2075 27619aac Thomas Thrainer
                                   constants.IDISK_MODE: "invalid"
2076 27619aac Thomas Thrainer
                                 }]])
2077 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2078 27619aac Thomas Thrainer
      op, "Invalid disk access mode 'invalid'")
2079 27619aac Thomas Thrainer
2080 27619aac Thomas Thrainer
  def testAddDiskMissingSize(self):
2081 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2082 27619aac Thomas Thrainer
                         disks=[[constants.DDM_ADD, -1, {}]])
2083 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2084 27619aac Thomas Thrainer
      op, "Required disk parameter 'size' missing")
2085 27619aac Thomas Thrainer
2086 27619aac Thomas Thrainer
  def testAddDiskInvalidSize(self):
2087 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2088 27619aac Thomas Thrainer
                         disks=[[constants.DDM_ADD, -1,
2089 27619aac Thomas Thrainer
                                 {
2090 27619aac Thomas Thrainer
                                   constants.IDISK_SIZE: "invalid"
2091 27619aac Thomas Thrainer
                                 }]])
2092 27619aac Thomas Thrainer
    self.ExecOpCodeExpectException(
2093 27619aac Thomas Thrainer
      op, errors.TypeEnforcementError, "is not a valid size")
2094 27619aac Thomas Thrainer
2095 27619aac Thomas Thrainer
  def testAddDisk(self):
2096 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2097 27619aac Thomas Thrainer
                         disks=[[constants.DDM_ADD, -1,
2098 27619aac Thomas Thrainer
                                 {
2099 27619aac Thomas Thrainer
                                   constants.IDISK_SIZE: 1024
2100 27619aac Thomas Thrainer
                                 }]])
2101 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2102 27619aac Thomas Thrainer
2103 27619aac Thomas Thrainer
  def testAddDiskNoneName(self):
2104 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2105 27619aac Thomas Thrainer
                         disks=[[constants.DDM_ADD, -1,
2106 27619aac Thomas Thrainer
                                 {
2107 27619aac Thomas Thrainer
                                   constants.IDISK_SIZE: 1024,
2108 27619aac Thomas Thrainer
                                   constants.IDISK_NAME: constants.VALUE_NONE
2109 27619aac Thomas Thrainer
                                 }]])
2110 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2111 27619aac Thomas Thrainer
2112 27619aac Thomas Thrainer
  def testModifyDiskWithSize(self):
2113 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2114 27619aac Thomas Thrainer
                         disks=[[constants.DDM_MODIFY, 0,
2115 27619aac Thomas Thrainer
                                 {
2116 27619aac Thomas Thrainer
                                   constants.IDISK_SIZE: 1024
2117 27619aac Thomas Thrainer
                                 }]])
2118 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2119 27619aac Thomas Thrainer
      op, "Disk size change not possible, use grow-disk")
2120 27619aac Thomas Thrainer
2121 27619aac Thomas Thrainer
  def testModifyDiskWithRandomParams(self):
2122 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2123 27619aac Thomas Thrainer
                         disks=[[constants.DDM_MODIFY, 0,
2124 27619aac Thomas Thrainer
                                 {
2125 27619aac Thomas Thrainer
                                   constants.IDISK_METAVG: "new_meta_vg",
2126 27619aac Thomas Thrainer
                                   constants.IDISK_MODE: "invalid",
2127 27619aac Thomas Thrainer
                                   constants.IDISK_NAME: "new_name"
2128 27619aac Thomas Thrainer
                                 }]])
2129 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2130 27619aac Thomas Thrainer
      op, "Disk modification doesn't support additional arbitrary parameters")
2131 27619aac Thomas Thrainer
2132 27619aac Thomas Thrainer
  def testModifyDiskUnsetName(self):
2133 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2134 27619aac Thomas Thrainer
                         disks=[[constants.DDM_MODIFY, 0,
2135 27619aac Thomas Thrainer
                                  {
2136 27619aac Thomas Thrainer
                                    constants.IDISK_NAME: constants.VALUE_NONE
2137 27619aac Thomas Thrainer
                                  }]])
2138 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2139 27619aac Thomas Thrainer
2140 27619aac Thomas Thrainer
  def testSetOldDiskTemplate(self):
2141 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2142 27619aac Thomas Thrainer
                         disk_template=self.inst.disk_template)
2143 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2144 27619aac Thomas Thrainer
      op, "Instance already has disk template")
2145 27619aac Thomas Thrainer
2146 27619aac Thomas Thrainer
  def testSetDisabledDiskTemplate(self):
2147 27619aac Thomas Thrainer
    self.cfg.SetEnabledDiskTemplates([self.inst.disk_template])
2148 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2149 27619aac Thomas Thrainer
                         disk_template=constants.DT_EXT)
2150 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2151 27619aac Thomas Thrainer
      op, "Disk template .* is not enabled for this cluster")
2152 27619aac Thomas Thrainer
2153 27619aac Thomas Thrainer
  def testInvalidDiskTemplateConversion(self):
2154 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2155 27619aac Thomas Thrainer
                         disk_template=constants.DT_EXT)
2156 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2157 27619aac Thomas Thrainer
      op, "Unsupported disk template conversion from .* to .*")
2158 27619aac Thomas Thrainer
2159 27619aac Thomas Thrainer
  def testConvertToDRBDWithSecondarySameAsPrimary(self):
2160 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2161 27619aac Thomas Thrainer
                         disk_template=constants.DT_DRBD8,
2162 27619aac Thomas Thrainer
                         remote_node=self.master.name)
2163 27619aac Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2164 27619aac Thomas Thrainer
      op, "Given new secondary node .* is the same as the primary node"
2165 27619aac Thomas Thrainer
          " of the instance")
2166 27619aac Thomas Thrainer
2167 27619aac Thomas Thrainer
  def testConvertPlainToDRBD(self):
2168 27619aac Thomas Thrainer
    self.rpc.call_blockdev_shutdown.return_value = \
2169 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
2170 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, True)
2171 27619aac Thomas Thrainer
    self.rpc.call_blockdev_getmirrorstatus.return_value = \
2172 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
2173 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, [objects.BlockDevStatus()])
2174 27619aac Thomas Thrainer
2175 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2176 27619aac Thomas Thrainer
                         disk_template=constants.DT_DRBD8,
2177 27619aac Thomas Thrainer
                         remote_node=self.snode.name)
2178 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2179 27619aac Thomas Thrainer
2180 27619aac Thomas Thrainer
  def testConvertDRBDToPlain(self):
2181 27619aac Thomas Thrainer
    self.inst.disks = [self.cfg.CreateDisk(dev_type=constants.DT_DRBD8,
2182 27619aac Thomas Thrainer
                                           primary_node=self.master,
2183 27619aac Thomas Thrainer
                                           secondary_node=self.snode)]
2184 27619aac Thomas Thrainer
    self.inst.disk_template = constants.DT_DRBD8
2185 27619aac Thomas Thrainer
    self.rpc.call_blockdev_shutdown.return_value = \
2186 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
2187 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, True)
2188 27619aac Thomas Thrainer
    self.rpc.call_blockdev_remove.return_value = \
2189 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
2190 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master)
2191 27619aac Thomas Thrainer
    self.rpc.call_blockdev_getmirrorstatus.return_value = \
2192 27619aac Thomas Thrainer
      self.RpcResultsBuilder() \
2193 27619aac Thomas Thrainer
        .CreateSuccessfulNodeResult(self.master, [objects.BlockDevStatus()])
2194 27619aac Thomas Thrainer
2195 27619aac Thomas Thrainer
    op = self.CopyOpCode(self.op,
2196 27619aac Thomas Thrainer
                         disk_template=constants.DT_PLAIN)
2197 27619aac Thomas Thrainer
    self.ExecOpCode(op)
2198 27619aac Thomas Thrainer
2199 27619aac Thomas Thrainer
2200 b02063fe Thomas Thrainer
class TestLUInstanceChangeGroup(CmdlibTestCase):
2201 b02063fe Thomas Thrainer
  def setUp(self):
2202 b02063fe Thomas Thrainer
    super(TestLUInstanceChangeGroup, self).setUp()
2203 b02063fe Thomas Thrainer
2204 b02063fe Thomas Thrainer
    self.group2 = self.cfg.AddNewNodeGroup()
2205 b02063fe Thomas Thrainer
    self.node2 = self.cfg.AddNewNode(group=self.group2)
2206 b02063fe Thomas Thrainer
    self.inst = self.cfg.AddNewInstance()
2207 b02063fe Thomas Thrainer
    self.op = opcodes.OpInstanceChangeGroup(instance_name=self.inst.name)
2208 b02063fe Thomas Thrainer
2209 b02063fe Thomas Thrainer
  def testTargetGroupIsInstanceGroup(self):
2210 b02063fe Thomas Thrainer
    op = self.CopyOpCode(self.op,
2211 b02063fe Thomas Thrainer
                         target_groups=[self.group.name])
2212 b02063fe Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2213 b02063fe Thomas Thrainer
      op, "Can't use group\(s\) .* as targets, they are used by the"
2214 b02063fe Thomas Thrainer
          " instance .*")
2215 b02063fe Thomas Thrainer
2216 b02063fe Thomas Thrainer
  def testNoTargetGroups(self):
2217 b02063fe Thomas Thrainer
    inst = self.cfg.AddNewInstance(disk_template=constants.DT_DRBD8,
2218 b02063fe Thomas Thrainer
                                   primary_node=self.master,
2219 b02063fe Thomas Thrainer
                                   secondary_node=self.node2)
2220 b02063fe Thomas Thrainer
    op = self.CopyOpCode(self.op,
2221 b02063fe Thomas Thrainer
                         instance_name=inst.name)
2222 b02063fe Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2223 b02063fe Thomas Thrainer
      op, "There are no possible target groups")
2224 b02063fe Thomas Thrainer
2225 b02063fe Thomas Thrainer
  def testFailingIAllocator(self):
2226 b02063fe Thomas Thrainer
    self.iallocator_cls.return_value.success = False
2227 b02063fe Thomas Thrainer
    op = self.CopyOpCode(self.op)
2228 b02063fe Thomas Thrainer
2229 b02063fe Thomas Thrainer
    self.ExecOpCodeExpectOpPrereqError(
2230 b02063fe Thomas Thrainer
      op, "Can't compute solution for changing group of instance .*"
2231 b02063fe Thomas Thrainer
          " using iallocator .*")
2232 b02063fe Thomas Thrainer
2233 b02063fe Thomas Thrainer
  def testChangeGroup(self):
2234 b02063fe Thomas Thrainer
    self.iallocator_cls.return_value.success = True
2235 b02063fe Thomas Thrainer
    self.iallocator_cls.return_value.result = ([], [], [])
2236 b02063fe Thomas Thrainer
    op = self.CopyOpCode(self.op)
2237 b02063fe Thomas Thrainer
2238 b02063fe Thomas Thrainer
    self.ExecOpCode(op)
2239 b02063fe Thomas Thrainer
2240 b02063fe Thomas Thrainer
2241 66222813 Thomas Thrainer
if __name__ == "__main__":
2242 66222813 Thomas Thrainer
  testutils.GanetiTestProgram()