Statistics
| Branch: | Tag: | Revision:

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

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