Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / instance_unittest.py @ d43a4dd9

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