Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / cluster_unittest.py @ 70e8dd0a

History | View | Annotate | Download (75.1 kB)

1
#!/usr/bin/python
2
#
3

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

    
21

    
22
"""Tests for LUCluster*
23

24
"""
25

    
26
import OpenSSL
27

    
28
import unittest
29
import operator
30
import os
31
import tempfile
32
import shutil
33

    
34
from ganeti import constants
35
from ganeti import errors
36
from ganeti import netutils
37
from ganeti import objects
38
from ganeti import opcodes
39
from ganeti import utils
40
from ganeti import pathutils
41
from ganeti import query
42
from ganeti.cmdlib import cluster
43
from ganeti.hypervisor import hv_xen
44

    
45
from testsupport import *
46

    
47
import testutils
48

    
49

    
50
class TestCertVerification(testutils.GanetiTestCase):
51
  def setUp(self):
52
    testutils.GanetiTestCase.setUp(self)
53

    
54
    self.tmpdir = tempfile.mkdtemp()
55

    
56
  def tearDown(self):
57
    shutil.rmtree(self.tmpdir)
58

    
59
  def testVerifyCertificate(self):
60
    cluster._VerifyCertificate(testutils.TestDataFilename("cert1.pem"))
61

    
62
    nonexist_filename = os.path.join(self.tmpdir, "does-not-exist")
63

    
64
    (errcode, msg) = cluster._VerifyCertificate(nonexist_filename)
65
    self.assertEqual(errcode, cluster.LUClusterVerifyConfig.ETYPE_ERROR)
66

    
67
    # Try to load non-certificate file
68
    invalid_cert = testutils.TestDataFilename("bdev-net.txt")
69
    (errcode, msg) = cluster._VerifyCertificate(invalid_cert)
70
    self.assertEqual(errcode, cluster.LUClusterVerifyConfig.ETYPE_ERROR)
71

    
72

    
73
class TestClusterVerifySsh(unittest.TestCase):
74
  def testMultipleGroups(self):
75
    fn = cluster.LUClusterVerifyGroup._SelectSshCheckNodes
76
    mygroupnodes = [
77
      objects.Node(name="node20", group="my", offline=False),
78
      objects.Node(name="node21", group="my", offline=False),
79
      objects.Node(name="node22", group="my", offline=False),
80
      objects.Node(name="node23", group="my", offline=False),
81
      objects.Node(name="node24", group="my", offline=False),
82
      objects.Node(name="node25", group="my", offline=False),
83
      objects.Node(name="node26", group="my", offline=True),
84
      ]
85
    nodes = [
86
      objects.Node(name="node1", group="g1", offline=True),
87
      objects.Node(name="node2", group="g1", offline=False),
88
      objects.Node(name="node3", group="g1", offline=False),
89
      objects.Node(name="node4", group="g1", offline=True),
90
      objects.Node(name="node5", group="g1", offline=False),
91
      objects.Node(name="node10", group="xyz", offline=False),
92
      objects.Node(name="node11", group="xyz", offline=False),
93
      objects.Node(name="node40", group="alloff", offline=True),
94
      objects.Node(name="node41", group="alloff", offline=True),
95
      objects.Node(name="node50", group="aaa", offline=False),
96
      ] + mygroupnodes
97
    assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes))
98

    
99
    (online, perhost) = fn(mygroupnodes, "my", nodes)
100
    self.assertEqual(online, ["node%s" % i for i in range(20, 26)])
101
    self.assertEqual(set(perhost.keys()), set(online))
102

    
103
    self.assertEqual(perhost, {
104
      "node20": ["node10", "node2", "node50"],
105
      "node21": ["node11", "node3", "node50"],
106
      "node22": ["node10", "node5", "node50"],
107
      "node23": ["node11", "node2", "node50"],
108
      "node24": ["node10", "node3", "node50"],
109
      "node25": ["node11", "node5", "node50"],
110
      })
111

    
112
  def testSingleGroup(self):
113
    fn = cluster.LUClusterVerifyGroup._SelectSshCheckNodes
114
    nodes = [
115
      objects.Node(name="node1", group="default", offline=True),
116
      objects.Node(name="node2", group="default", offline=False),
117
      objects.Node(name="node3", group="default", offline=False),
118
      objects.Node(name="node4", group="default", offline=True),
119
      ]
120
    assert not utils.FindDuplicates(map(operator.attrgetter("name"), nodes))
121

    
122
    (online, perhost) = fn(nodes, "default", nodes)
123
    self.assertEqual(online, ["node2", "node3"])
124
    self.assertEqual(set(perhost.keys()), set(online))
125

    
126
    self.assertEqual(perhost, {
127
      "node2": [],
128
      "node3": [],
129
      })
130

    
131

    
132
class TestLUClusterActivateMasterIp(CmdlibTestCase):
133
  def testSuccess(self):
134
    op = opcodes.OpClusterActivateMasterIp()
135

    
136
    self.rpc.call_node_activate_master_ip.return_value = \
137
      self.RpcResultsBuilder() \
138
        .CreateSuccessfulNodeResult(self.master)
139

    
140
    self.ExecOpCode(op)
141

    
142
    self.rpc.call_node_activate_master_ip.assert_called_once_with(
143
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
144

    
145
  def testFailure(self):
146
    op = opcodes.OpClusterActivateMasterIp()
147

    
148
    self.rpc.call_node_activate_master_ip.return_value = \
149
      self.RpcResultsBuilder() \
150
        .CreateFailedNodeResult(self.master) \
151

    
152
    self.ExecOpCodeExpectOpExecError(op)
153

    
154

    
155
class TestLUClusterDeactivateMasterIp(CmdlibTestCase):
156
  def testSuccess(self):
157
    op = opcodes.OpClusterDeactivateMasterIp()
158

    
159
    self.rpc.call_node_deactivate_master_ip.return_value = \
160
      self.RpcResultsBuilder() \
161
        .CreateSuccessfulNodeResult(self.master)
162

    
163
    self.ExecOpCode(op)
164

    
165
    self.rpc.call_node_deactivate_master_ip.assert_called_once_with(
166
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
167

    
168
  def testFailure(self):
169
    op = opcodes.OpClusterDeactivateMasterIp()
170

    
171
    self.rpc.call_node_deactivate_master_ip.return_value = \
172
      self.RpcResultsBuilder() \
173
        .CreateFailedNodeResult(self.master) \
174

    
175
    self.ExecOpCodeExpectOpExecError(op)
176

    
177

    
178
class TestLUClusterConfigQuery(CmdlibTestCase):
179
  def testInvalidField(self):
180
    op = opcodes.OpClusterConfigQuery(output_fields=["pinky_bunny"])
181

    
182
    self.ExecOpCodeExpectOpPrereqError(op, "pinky_bunny")
183

    
184
  def testAllFields(self):
185
    op = opcodes.OpClusterConfigQuery(output_fields=query.CLUSTER_FIELDS.keys())
186

    
187
    self.rpc.call_get_watcher_pause.return_value = \
188
      self.RpcResultsBuilder() \
189
        .CreateSuccessfulNodeResult(self.master, -1)
190

    
191
    ret = self.ExecOpCode(op)
192

    
193
    self.assertEqual(1, self.rpc.call_get_watcher_pause.call_count)
194
    self.assertEqual(len(ret), len(query.CLUSTER_FIELDS))
195

    
196
  def testEmpytFields(self):
197
    op = opcodes.OpClusterConfigQuery(output_fields=[])
198

    
199
    self.ExecOpCode(op)
200

    
201
    self.assertFalse(self.rpc.call_get_watcher_pause.called)
202

    
203

    
204
class TestLUClusterDestroy(CmdlibTestCase):
205
  def testExistingNodes(self):
206
    op = opcodes.OpClusterDestroy()
207

    
208
    self.cfg.AddNewNode()
209
    self.cfg.AddNewNode()
210

    
211
    self.ExecOpCodeExpectOpPrereqError(op, "still 2 node\(s\)")
212

    
213
  def testExistingInstances(self):
214
    op = opcodes.OpClusterDestroy()
215

    
216
    self.cfg.AddNewInstance()
217
    self.cfg.AddNewInstance()
218

    
219
    self.ExecOpCodeExpectOpPrereqError(op, "still 2 instance\(s\)")
220

    
221
  def testEmptyCluster(self):
222
    op = opcodes.OpClusterDestroy()
223

    
224
    self.ExecOpCode(op)
225

    
226
    self.assertSingleHooksCall([self.master.name],
227
                               "cluster-destroy",
228
                               constants.HOOKS_PHASE_POST)
229

    
230

    
231
class TestLUClusterPostInit(CmdlibTestCase):
232
  def testExecuion(self):
233
    op = opcodes.OpClusterPostInit()
234

    
235
    self.ExecOpCode(op)
236

    
237
    self.assertSingleHooksCall([self.master.name],
238
                               "cluster-init",
239
                               constants.HOOKS_PHASE_POST)
240

    
241

    
242
class TestLUClusterQuery(CmdlibTestCase):
243
  def testSimpleInvocation(self):
244
    op = opcodes.OpClusterQuery()
245

    
246
    self.ExecOpCode(op)
247

    
248
  def testIPv6Cluster(self):
249
    op = opcodes.OpClusterQuery()
250

    
251
    self.cluster.primary_ip_family = netutils.IP6Address.family
252

    
253
    self.ExecOpCode(op)
254

    
255

    
256
class TestLUClusterRedistConf(CmdlibTestCase):
257
  def testSimpleInvocation(self):
258
    op = opcodes.OpClusterRedistConf()
259

    
260
    self.ExecOpCode(op)
261

    
262

    
263
class TestLUClusterRename(CmdlibTestCase):
264
  NEW_NAME = "new-name.example.com"
265
  NEW_IP = "203.0.113.100"
266

    
267
  def testNoChanges(self):
268
    op = opcodes.OpClusterRename(name=self.cfg.GetClusterName())
269

    
270
    self.ExecOpCodeExpectOpPrereqError(op, "name nor the IP address")
271

    
272
  def testReachableIp(self):
273
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
274

    
275
    self.netutils_mod.GetHostname.return_value = \
276
      HostnameMock(self.NEW_NAME, self.NEW_IP)
277
    self.netutils_mod.TcpPing.return_value = True
278

    
279
    self.ExecOpCodeExpectOpPrereqError(op, "is reachable on the network")
280

    
281
  def testValidRename(self):
282
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
283

    
284
    self.netutils_mod.GetHostname.return_value = \
285
      HostnameMock(self.NEW_NAME, self.NEW_IP)
286

    
287
    self.ExecOpCode(op)
288

    
289
    self.assertEqual(1, self.ssh_mod.WriteKnownHostsFile.call_count)
290
    self.rpc.call_node_deactivate_master_ip.assert_called_once_with(
291
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
292
    self.rpc.call_node_activate_master_ip.assert_called_once_with(
293
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
294

    
295
  def testRenameOfflineMaster(self):
296
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
297

    
298
    self.master.offline = True
299
    self.netutils_mod.GetHostname.return_value = \
300
      HostnameMock(self.NEW_NAME, self.NEW_IP)
301

    
302
    self.ExecOpCode(op)
303

    
304

    
305
class TestLUClusterRepairDiskSizes(CmdlibTestCase):
306
  def testNoInstances(self):
307
    op = opcodes.OpClusterRepairDiskSizes()
308

    
309
    self.ExecOpCode(op)
310

    
311
  def _SetUpInstanceSingleDisk(self, dev_type=constants.DT_PLAIN):
312
    pnode = self.master
313
    snode = self.cfg.AddNewNode()
314

    
315
    disk = self.cfg.CreateDisk(dev_type=dev_type,
316
                               primary_node=pnode,
317
                               secondary_node=snode)
318
    inst = self.cfg.AddNewInstance(disks=[disk])
319

    
320
    return (inst, disk)
321

    
322
  def testSingleInstanceOnFailingNode(self):
323
    (inst, _) = self._SetUpInstanceSingleDisk()
324
    op = opcodes.OpClusterRepairDiskSizes(instances=[inst.name])
325

    
326
    self.rpc.call_blockdev_getdimensions.return_value = \
327
      self.RpcResultsBuilder() \
328
        .CreateFailedNodeResult(self.master)
329

    
330
    self.ExecOpCode(op)
331

    
332
    self.mcpu.assertLogContainsRegex("Failure in blockdev_getdimensions")
333

    
334
  def _ExecOpClusterRepairDiskSizes(self, node_data):
335
    # not specifying instances repairs all
336
    op = opcodes.OpClusterRepairDiskSizes()
337

    
338
    self.rpc.call_blockdev_getdimensions.return_value = \
339
      self.RpcResultsBuilder() \
340
        .CreateSuccessfulNodeResult(self.master, node_data)
341

    
342
    return self.ExecOpCode(op)
343

    
344
  def testInvalidResultData(self):
345
    for data in [[], [None], ["invalid"], [("still", "invalid")]]:
346
      self.ResetMocks()
347

    
348
      self._SetUpInstanceSingleDisk()
349
      self._ExecOpClusterRepairDiskSizes(data)
350

    
351
      self.mcpu.assertLogContainsRegex("ignoring")
352

    
353
  def testCorrectSize(self):
354
    self._SetUpInstanceSingleDisk()
355
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
356
    self.mcpu.assertLogIsEmpty()
357
    self.assertEqual(0, len(changed))
358

    
359
  def testWrongSize(self):
360
    self._SetUpInstanceSingleDisk()
361
    changed = self._ExecOpClusterRepairDiskSizes([(512 * 1024 * 1024, None)])
362
    self.assertEqual(1, len(changed))
363

    
364
  def testCorrectDRBD(self):
365
    self._SetUpInstanceSingleDisk(dev_type=constants.DT_DRBD8)
366
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
367
    self.mcpu.assertLogIsEmpty()
368
    self.assertEqual(0, len(changed))
369

    
370
  def testWrongDRBDChild(self):
371
    (_, disk) = self._SetUpInstanceSingleDisk(dev_type=constants.DT_DRBD8)
372
    disk.children[0].size = 512
373
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
374
    self.assertEqual(1, len(changed))
375

    
376
  def testExclusiveStorageInvalidResultData(self):
377
    self._SetUpInstanceSingleDisk()
378
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
379
    self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
380

    
381
    self.mcpu.assertLogContainsRegex(
382
      "did not return valid spindles information")
383

    
384
  def testExclusiveStorageCorrectSpindles(self):
385
    (_, disk) = self._SetUpInstanceSingleDisk()
386
    disk.spindles = 1
387
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
388
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
389
    self.assertEqual(0, len(changed))
390

    
391
  def testExclusiveStorageWrongSpindles(self):
392
    self._SetUpInstanceSingleDisk()
393
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
394
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
395
    self.assertEqual(1, len(changed))
396

    
397

    
398
class TestLUClusterSetParams(CmdlibTestCase):
399
  UID_POOL = [(10, 1000)]
400

    
401
  def testUidPool(self):
402
    op = opcodes.OpClusterSetParams(uid_pool=self.UID_POOL)
403
    self.ExecOpCode(op)
404
    self.assertEqual(self.UID_POOL, self.cluster.uid_pool)
405

    
406
  def testAddUids(self):
407
    old_pool = [(1, 9)]
408
    self.cluster.uid_pool = list(old_pool)
409
    op = opcodes.OpClusterSetParams(add_uids=self.UID_POOL)
410
    self.ExecOpCode(op)
411
    self.assertEqual(set(self.UID_POOL + old_pool),
412
                     set(self.cluster.uid_pool))
413

    
414
  def testRemoveUids(self):
415
    additional_pool = [(1, 9)]
416
    self.cluster.uid_pool = self.UID_POOL + additional_pool
417
    op = opcodes.OpClusterSetParams(remove_uids=self.UID_POOL)
418
    self.ExecOpCode(op)
419
    self.assertEqual(additional_pool, self.cluster.uid_pool)
420

    
421
  def testMasterNetmask(self):
422
    op = opcodes.OpClusterSetParams(master_netmask=26)
423
    self.ExecOpCode(op)
424
    self.assertEqual(26, self.cluster.master_netmask)
425

    
426
  def testInvalidDiskparams(self):
427
    for diskparams in [{constants.DT_DISKLESS: {constants.LV_STRIPES: 0}},
428
                       {constants.DT_DRBD8: {constants.RBD_POOL: "pool"}},
429
                       {constants.DT_DRBD8: {constants.RBD_ACCESS: "bunny"}}]:
430
      self.ResetMocks()
431
      op = opcodes.OpClusterSetParams(diskparams=diskparams)
432
      self.ExecOpCodeExpectOpPrereqError(op, "verify diskparams")
433

    
434
  def testValidDiskparams(self):
435
    diskparams = {constants.DT_RBD: {constants.RBD_POOL: "mock_pool",
436
                                     constants.RBD_ACCESS: "kernelspace"}}
437
    op = opcodes.OpClusterSetParams(diskparams=diskparams)
438
    self.ExecOpCode(op)
439
    self.assertEqual(diskparams[constants.DT_RBD],
440
                     self.cluster.diskparams[constants.DT_RBD])
441

    
442
  def testMinimalDiskparams(self):
443
    diskparams = {constants.DT_RBD: {constants.RBD_POOL: "mock_pool"}}
444
    self.cluster.diskparams = {}
445
    op = opcodes.OpClusterSetParams(diskparams=diskparams)
446
    self.ExecOpCode(op)
447
    self.assertEqual(diskparams, self.cluster.diskparams)
448

    
449
  def testValidDiskparamsAccess(self):
450
    for value in constants.DISK_VALID_ACCESS_MODES:
451
      self.ResetMocks()
452
      op = opcodes.OpClusterSetParams(diskparams={
453
        constants.DT_RBD: {constants.RBD_ACCESS: value}
454
      })
455
      self.ExecOpCode(op)
456
      got = self.cluster.diskparams[constants.DT_RBD][constants.RBD_ACCESS]
457
      self.assertEqual(value, got)
458

    
459
  def testInvalidDiskparamsAccess(self):
460
    for value in ["default", "pinky_bunny"]:
461
      self.ResetMocks()
462
      op = opcodes.OpClusterSetParams(diskparams={
463
        constants.DT_RBD: {constants.RBD_ACCESS: value}
464
      })
465
      self.ExecOpCodeExpectOpPrereqError(op, "Invalid value of 'rbd:access'")
466

    
467
  def testUnsetDrbdHelperWithDrbdDisks(self):
468
    self.cfg.AddNewInstance(disks=[
469
      self.cfg.CreateDisk(dev_type=constants.DT_DRBD8, create_nodes=True)])
470
    op = opcodes.OpClusterSetParams(drbd_helper="")
471
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable drbd helper")
472

    
473
  def testFileStorageDir(self):
474
    op = opcodes.OpClusterSetParams(file_storage_dir="/random/path")
475
    self.ExecOpCode(op)
476

    
477
  def testSetFileStorageDirToCurrentValue(self):
478
    op = opcodes.OpClusterSetParams(
479
           file_storage_dir=self.cluster.file_storage_dir)
480
    self.ExecOpCode(op)
481

    
482
    self.mcpu.assertLogContainsRegex("file storage dir already set to value")
483

    
484
  def testUnsetFileStorageDirFileStorageEnabled(self):
485
    self.cfg.SetEnabledDiskTemplates([constants.DT_FILE])
486
    op = opcodes.OpClusterSetParams(file_storage_dir='')
487
    self.ExecOpCodeExpectOpPrereqError(op, "Unsetting the 'file' storage")
488

    
489
  def testUnsetFileStorageDirFileStorageDisabled(self):
490
    self.cfg.SetEnabledDiskTemplates([constants.DT_PLAIN])
491
    op = opcodes.OpClusterSetParams(file_storage_dir='')
492
    self.ExecOpCode(op)
493

    
494
  def testSetFileStorageDirFileStorageDisabled(self):
495
    self.cfg.SetEnabledDiskTemplates([constants.DT_PLAIN])
496
    op = opcodes.OpClusterSetParams(file_storage_dir='/some/path/')
497
    self.ExecOpCode(op)
498
    self.mcpu.assertLogContainsRegex("although file storage is not enabled")
499

    
500
  def testValidDrbdHelper(self):
501
    node1 = self.cfg.AddNewNode()
502
    node1.offline = True
503
    self.rpc.call_drbd_helper.return_value = \
504
      self.RpcResultsBuilder() \
505
        .AddSuccessfulNode(self.master, "/bin/true") \
506
        .AddOfflineNode(node1) \
507
        .Build()
508
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
509
    self.ExecOpCode(op)
510
    self.mcpu.assertLogContainsRegex("Not checking drbd helper on offline node")
511

    
512
  def testDrbdHelperFailingNode(self):
513
    self.rpc.call_drbd_helper.return_value = \
514
      self.RpcResultsBuilder() \
515
        .AddFailedNode(self.master) \
516
        .Build()
517
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
518
    self.ExecOpCodeExpectOpPrereqError(op, "Error checking drbd helper")
519

    
520
  def testInvalidDrbdHelper(self):
521
    self.rpc.call_drbd_helper.return_value = \
522
      self.RpcResultsBuilder() \
523
        .AddSuccessfulNode(self.master, "/bin/false") \
524
        .Build()
525
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
526
    self.ExecOpCodeExpectOpPrereqError(op, "drbd helper is /bin/false")
527

    
528
  def testDrbdHelperWithoutDrbdDiskTemplate(self):
529
    drbd_helper = "/bin/random_helper"
530
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
531
    self.rpc.call_drbd_helper.return_value = \
532
      self.RpcResultsBuilder() \
533
        .AddSuccessfulNode(self.master, drbd_helper) \
534
        .Build()
535
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
536
    self.ExecOpCode(op)
537

    
538
    self.mcpu.assertLogContainsRegex("but did not enable")
539

    
540
  def testResetDrbdHelperDrbdDisabled(self):
541
    drbd_helper = ""
542
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
543
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
544
    self.ExecOpCode(op)
545

    
546
    self.assertEqual(None, self.cluster.drbd_usermode_helper)
547

    
548
  def testResetDrbdHelperDrbdEnabled(self):
549
    drbd_helper = ""
550
    self.cluster.enabled_disk_templates = [constants.DT_DRBD8]
551
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
552
    self.ExecOpCodeExpectOpPrereqError(
553
        op, "Cannot disable drbd helper while DRBD is enabled.")
554

    
555
  def testEnableDrbdNoHelper(self):
556
    self.cluster.enabled_disk_templates = [constants.DT_DISKLESS]
557
    self.cluster.drbd_usermode_helper = None
558
    enabled_disk_templates = [constants.DT_DRBD8]
559
    op = opcodes.OpClusterSetParams(
560
        enabled_disk_templates=enabled_disk_templates)
561
    self.ExecOpCodeExpectOpPrereqError(
562
        op, "Cannot enable DRBD without a DRBD usermode helper set")
563

    
564
  def testEnableDrbdHelperSet(self):
565
    drbd_helper = "/bin/random_helper"
566
    self.rpc.call_drbd_helper.return_value = \
567
      self.RpcResultsBuilder() \
568
        .AddSuccessfulNode(self.master, drbd_helper) \
569
        .Build()
570
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
571
    self.cluster.drbd_usermode_helper = drbd_helper
572
    enabled_disk_templates = [constants.DT_DRBD8]
573
    op = opcodes.OpClusterSetParams(
574
        enabled_disk_templates=enabled_disk_templates,
575
        ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
576
    self.ExecOpCode(op)
577

    
578
    self.assertEqual(drbd_helper, self.cluster.drbd_usermode_helper)
579

    
580
  def testDrbdHelperAlreadySet(self):
581
    drbd_helper = "/bin/true"
582
    self.rpc.call_drbd_helper.return_value = \
583
      self.RpcResultsBuilder() \
584
        .AddSuccessfulNode(self.master, "/bin/true") \
585
        .Build()
586
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
587
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
588
    self.ExecOpCode(op)
589

    
590
    self.assertEqual(drbd_helper, self.cluster.drbd_usermode_helper)
591
    self.mcpu.assertLogContainsRegex("DRBD helper already in desired state")
592

    
593
  def testSetDrbdHelper(self):
594
    drbd_helper = "/bin/true"
595
    self.rpc.call_drbd_helper.return_value = \
596
      self.RpcResultsBuilder() \
597
        .AddSuccessfulNode(self.master, "/bin/true") \
598
        .Build()
599
    self.cluster.drbd_usermode_helper = "/bin/false"
600
    self.cfg.SetEnabledDiskTemplates([constants.DT_DRBD8])
601
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
602
    self.ExecOpCode(op)
603

    
604
    self.assertEqual(drbd_helper, self.cluster.drbd_usermode_helper)
605

    
606
  def testBeparams(self):
607
    beparams = {constants.BE_VCPUS: 32}
608
    op = opcodes.OpClusterSetParams(beparams=beparams)
609
    self.ExecOpCode(op)
610
    self.assertEqual(32, self.cluster
611
                           .beparams[constants.PP_DEFAULT][constants.BE_VCPUS])
612

    
613
  def testNdparams(self):
614
    ndparams = {constants.ND_EXCLUSIVE_STORAGE: True}
615
    op = opcodes.OpClusterSetParams(ndparams=ndparams)
616
    self.ExecOpCode(op)
617
    self.assertEqual(True, self.cluster
618
                             .ndparams[constants.ND_EXCLUSIVE_STORAGE])
619

    
620
  def testNdparamsResetOobProgram(self):
621
    ndparams = {constants.ND_OOB_PROGRAM: ""}
622
    op = opcodes.OpClusterSetParams(ndparams=ndparams)
623
    self.ExecOpCode(op)
624
    self.assertEqual(constants.NDC_DEFAULTS[constants.ND_OOB_PROGRAM],
625
                     self.cluster.ndparams[constants.ND_OOB_PROGRAM])
626

    
627
  def testHvState(self):
628
    hv_state = {constants.HT_FAKE: {constants.HVST_CPU_TOTAL: 8}}
629
    op = opcodes.OpClusterSetParams(hv_state=hv_state)
630
    self.ExecOpCode(op)
631
    self.assertEqual(8, self.cluster.hv_state_static
632
                          [constants.HT_FAKE][constants.HVST_CPU_TOTAL])
633

    
634
  def testDiskState(self):
635
    disk_state = {
636
      constants.DT_PLAIN: {
637
        "mock_vg": {constants.DS_DISK_TOTAL: 10}
638
      }
639
    }
640
    op = opcodes.OpClusterSetParams(disk_state=disk_state)
641
    self.ExecOpCode(op)
642
    self.assertEqual(10, self.cluster
643
                           .disk_state_static[constants.DT_PLAIN]["mock_vg"]
644
                             [constants.DS_DISK_TOTAL])
645

    
646
  def testDefaultIPolicy(self):
647
    ipolicy = constants.IPOLICY_DEFAULTS
648
    op = opcodes.OpClusterSetParams(ipolicy=ipolicy)
649
    self.ExecOpCode(op)
650

    
651
  def testIPolicyNewViolation(self):
652
    import ganeti.constants as C
653
    ipolicy = C.IPOLICY_DEFAULTS
654
    ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MIN][C.ISPEC_MEM_SIZE] = 128
655
    ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MAX][C.ISPEC_MEM_SIZE] = 128
656

    
657
    self.cfg.AddNewInstance(beparams={C.BE_MINMEM: 512, C.BE_MAXMEM: 512})
658
    op = opcodes.OpClusterSetParams(ipolicy=ipolicy)
659
    self.ExecOpCode(op)
660

    
661
    self.mcpu.assertLogContainsRegex("instances violate them")
662

    
663
  def testNicparamsNoInstance(self):
664
    nicparams = {
665
      constants.NIC_LINK: "mock_bridge"
666
    }
667
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
668
    self.ExecOpCode(op)
669

    
670
    self.assertEqual("mock_bridge",
671
                     self.cluster.nicparams
672
                       [constants.PP_DEFAULT][constants.NIC_LINK])
673

    
674
  def testNicparamsInvalidConf(self):
675
    nicparams = {
676
      constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
677
      constants.NIC_LINK: ""
678
    }
679
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
680
    self.ExecOpCodeExpectException(op, errors.ConfigurationError, "NIC link")
681

    
682
  def testNicparamsInvalidInstanceConf(self):
683
    nicparams = {
684
      constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
685
      constants.NIC_LINK: "mock_bridge"
686
    }
687
    self.cfg.AddNewInstance(nics=[
688
      self.cfg.CreateNic(nicparams={constants.NIC_LINK: None})])
689
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
690
    self.ExecOpCodeExpectOpPrereqError(op, "Missing bridged NIC link")
691

    
692
  def testNicparamsMissingIp(self):
693
    nicparams = {
694
      constants.NIC_MODE: constants.NIC_MODE_ROUTED
695
    }
696
    self.cfg.AddNewInstance()
697
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
698
    self.ExecOpCodeExpectOpPrereqError(op, "routed NIC with no ip address")
699

    
700
  def testNicparamsWithInstance(self):
701
    nicparams = {
702
      constants.NIC_LINK: "mock_bridge"
703
    }
704
    self.cfg.AddNewInstance()
705
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
706
    self.ExecOpCode(op)
707

    
708
  def testDefaultHvparams(self):
709
    hvparams = constants.HVC_DEFAULTS
710
    op = opcodes.OpClusterSetParams(hvparams=hvparams)
711
    self.ExecOpCode(op)
712

    
713
    self.assertEqual(hvparams, self.cluster.hvparams)
714

    
715
  def testMinimalHvparams(self):
716
    hvparams = {
717
      constants.HT_FAKE: {
718
        constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE
719
      }
720
    }
721
    self.cluster.hvparams = {}
722
    op = opcodes.OpClusterSetParams(hvparams=hvparams)
723
    self.ExecOpCode(op)
724

    
725
    self.assertEqual(hvparams, self.cluster.hvparams)
726

    
727
  def testOsHvp(self):
728
    os_hvp = {
729
      "mocked_os": {
730
        constants.HT_FAKE: {
731
          constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE
732
        }
733
      },
734
      "other_os": constants.HVC_DEFAULTS
735
    }
736
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
737
    self.ExecOpCode(op)
738

    
739
    self.assertEqual(constants.HT_MIGRATION_NONLIVE,
740
                     self.cluster.os_hvp["mocked_os"][constants.HT_FAKE]
741
                       [constants.HV_MIGRATION_MODE])
742
    self.assertEqual(constants.HVC_DEFAULTS, self.cluster.os_hvp["other_os"])
743

    
744
  def testRemoveOsHvp(self):
745
    os_hvp = {"mocked_os": {constants.HT_FAKE: None}}
746
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
747
    self.ExecOpCode(op)
748

    
749
    assert constants.HT_FAKE not in self.cluster.os_hvp["mocked_os"]
750

    
751
  def testDefaultOsHvp(self):
752
    os_hvp = {"mocked_os": constants.HVC_DEFAULTS.copy()}
753
    self.cluster.os_hvp = {"mocked_os": {}}
754
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
755
    self.ExecOpCode(op)
756

    
757
    self.assertEqual(os_hvp, self.cluster.os_hvp)
758

    
759
  def testOsparams(self):
760
    osparams = {
761
      "mocked_os": {
762
        "param1": "value1",
763
        "param2": None
764
      },
765
      "other_os": {
766
        "param1": None
767
      }
768
    }
769
    self.cluster.osparams = {"other_os": {"param1": "value1"}}
770
    op = opcodes.OpClusterSetParams(osparams=osparams)
771
    self.ExecOpCode(op)
772

    
773
    self.assertEqual({"mocked_os": {"param1": "value1"}}, self.cluster.osparams)
774

    
775
  def testEnabledHypervisors(self):
776
    enabled_hypervisors = [constants.HT_XEN_HVM, constants.HT_XEN_PVM]
777
    op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors)
778
    self.ExecOpCode(op)
779

    
780
    self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors)
781

    
782
  def testEnabledHypervisorsWithoutHypervisorParams(self):
783
    enabled_hypervisors = [constants.HT_FAKE]
784
    self.cluster.hvparams = {}
785
    op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors)
786
    self.ExecOpCode(op)
787

    
788
    self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors)
789
    self.assertEqual(constants.HVC_DEFAULTS[constants.HT_FAKE],
790
                     self.cluster.hvparams[constants.HT_FAKE])
791

    
792
  @testutils.patch_object(utils, "FindFile")
793
  def testValidDefaultIallocator(self, find_file_mock):
794
    find_file_mock.return_value = "/random/path"
795
    default_iallocator = "/random/path"
796
    op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator)
797
    self.ExecOpCode(op)
798

    
799
    self.assertEqual(default_iallocator, self.cluster.default_iallocator)
800

    
801
  @testutils.patch_object(utils, "FindFile")
802
  def testInvalidDefaultIallocator(self, find_file_mock):
803
    find_file_mock.return_value = None
804
    default_iallocator = "/random/path"
805
    op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator)
806
    self.ExecOpCodeExpectOpPrereqError(op, "Invalid default iallocator script")
807

    
808
  def testEnabledDiskTemplates(self):
809
    enabled_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN]
810
    op = opcodes.OpClusterSetParams(
811
           enabled_disk_templates=enabled_disk_templates,
812
           ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
813
    self.ExecOpCode(op)
814

    
815
    self.assertEqual(enabled_disk_templates,
816
                     self.cluster.enabled_disk_templates)
817

    
818
  def testDisablingDiskTemplatesOfInstances(self):
819
    old_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN]
820
    self.cfg.SetEnabledDiskTemplates(old_disk_templates)
821
    self.cfg.AddNewInstance(
822
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_PLAIN)])
823
    new_disk_templates = [constants.DT_DISKLESS, constants.DT_DRBD8]
824
    op = opcodes.OpClusterSetParams(
825
           enabled_disk_templates=new_disk_templates,
826
           ipolicy={constants.IPOLICY_DTS: new_disk_templates})
827
    self.ExecOpCodeExpectOpPrereqError(op, "least one instance using it")
828

    
829
  def testEnabledDiskTemplatesWithoutVgName(self):
830
    enabled_disk_templates = [constants.DT_PLAIN]
831
    self.cluster.volume_group_name = None
832
    op = opcodes.OpClusterSetParams(
833
           enabled_disk_templates=enabled_disk_templates)
834
    self.ExecOpCodeExpectOpPrereqError(op, "specify a volume group")
835

    
836
  def testDisableDiskTemplateWithExistingInstance(self):
837
    enabled_disk_templates = [constants.DT_DISKLESS]
838
    self.cfg.AddNewInstance(
839
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_PLAIN)])
840
    op = opcodes.OpClusterSetParams(
841
           enabled_disk_templates=enabled_disk_templates,
842
           ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
843
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable disk template")
844

    
845
  def testVgNameNoLvmDiskTemplateEnabled(self):
846
    vg_name = "test_vg"
847
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
848
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
849
    self.ExecOpCode(op)
850

    
851
    self.assertEqual(vg_name, self.cluster.volume_group_name)
852
    self.mcpu.assertLogIsEmpty()
853

    
854
  def testUnsetVgNameWithLvmDiskTemplateEnabled(self):
855
    vg_name = ""
856
    self.cluster.enabled_disk_templates = [constants.DT_PLAIN]
857
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
858
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group")
859

    
860
  def testUnsetVgNameWithLvmInstance(self):
861
    vg_name = ""
862
    self.cfg.AddNewInstance(
863
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_PLAIN)])
864
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
865
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group")
866

    
867
  def testUnsetVgNameWithNoLvmDiskTemplateEnabled(self):
868
    vg_name = ""
869
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
870
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
871
    self.ExecOpCode(op)
872

    
873
    self.assertEqual(None, self.cluster.volume_group_name)
874

    
875
  def testVgNameToOldName(self):
876
    vg_name = self.cluster.volume_group_name
877
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
878
    self.ExecOpCode(op)
879

    
880
    self.mcpu.assertLogContainsRegex("already in desired state")
881

    
882
  def testVgNameWithFailingNode(self):
883
    vg_name = "test_vg"
884
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
885
    self.rpc.call_vg_list.return_value = \
886
      self.RpcResultsBuilder() \
887
        .AddFailedNode(self.master) \
888
        .Build()
889
    self.ExecOpCode(op)
890

    
891
    self.mcpu.assertLogContainsRegex("Error while gathering data on node")
892

    
893
  def testVgNameWithValidNode(self):
894
    vg_name = "test_vg"
895
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
896
    self.rpc.call_vg_list.return_value = \
897
      self.RpcResultsBuilder() \
898
        .AddSuccessfulNode(self.master, {vg_name: 1024 * 1024}) \
899
        .Build()
900
    self.ExecOpCode(op)
901

    
902
  def testVgNameWithTooSmallNode(self):
903
    vg_name = "test_vg"
904
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
905
    self.rpc.call_vg_list.return_value = \
906
      self.RpcResultsBuilder() \
907
        .AddSuccessfulNode(self.master, {vg_name: 1}) \
908
        .Build()
909
    self.ExecOpCodeExpectOpPrereqError(op, "too small")
910

    
911
  def testMiscParameters(self):
912
    op = opcodes.OpClusterSetParams(candidate_pool_size=123,
913
                                    maintain_node_health=True,
914
                                    modify_etc_hosts=True,
915
                                    prealloc_wipe_disks=True,
916
                                    reserved_lvs=["/dev/mock_lv"],
917
                                    use_external_mip_script=True)
918
    self.ExecOpCode(op)
919

    
920
    self.mcpu.assertLogIsEmpty()
921
    self.assertEqual(123, self.cluster.candidate_pool_size)
922
    self.assertEqual(True, self.cluster.maintain_node_health)
923
    self.assertEqual(True, self.cluster.modify_etc_hosts)
924
    self.assertEqual(True, self.cluster.prealloc_wipe_disks)
925
    self.assertEqual(["/dev/mock_lv"], self.cluster.reserved_lvs)
926
    self.assertEqual(True, self.cluster.use_external_mip_script)
927

    
928
  def testAddHiddenOs(self):
929
    self.cluster.hidden_os = ["hidden1", "hidden2"]
930
    op = opcodes.OpClusterSetParams(hidden_os=[(constants.DDM_ADD, "hidden2"),
931
                                               (constants.DDM_ADD, "hidden3")])
932
    self.ExecOpCode(op)
933

    
934
    self.assertEqual(["hidden1", "hidden2", "hidden3"], self.cluster.hidden_os)
935
    self.mcpu.assertLogContainsRegex("OS hidden2 already")
936

    
937
  def testRemoveBlacklistedOs(self):
938
    self.cluster.blacklisted_os = ["blisted1", "blisted2"]
939
    op = opcodes.OpClusterSetParams(blacklisted_os=[
940
                                      (constants.DDM_REMOVE, "blisted2"),
941
                                      (constants.DDM_REMOVE, "blisted3")])
942
    self.ExecOpCode(op)
943

    
944
    self.assertEqual(["blisted1"], self.cluster.blacklisted_os)
945
    self.mcpu.assertLogContainsRegex("OS blisted3 not found")
946

    
947
  def testMasterNetdev(self):
948
    master_netdev = "test_dev"
949
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev)
950
    self.ExecOpCode(op)
951

    
952
    self.assertEqual(master_netdev, self.cluster.master_netdev)
953

    
954
  def testMasterNetdevFailNoForce(self):
955
    master_netdev = "test_dev"
956
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev)
957
    self.rpc.call_node_deactivate_master_ip.return_value = \
958
      self.RpcResultsBuilder() \
959
        .CreateFailedNodeResult(self.master)
960
    self.ExecOpCodeExpectOpExecError(op, "Could not disable the master ip")
961

    
962
  def testMasterNetdevFailForce(self):
963
    master_netdev = "test_dev"
964
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev,
965
                                    force=True)
966
    self.rpc.call_node_deactivate_master_ip.return_value = \
967
      self.RpcResultsBuilder() \
968
        .CreateFailedNodeResult(self.master)
969
    self.ExecOpCode(op)
970

    
971
    self.mcpu.assertLogContainsRegex("Could not disable the master ip")
972

    
973

    
974
class TestLUClusterVerify(CmdlibTestCase):
975
  def testVerifyAllGroups(self):
976
    op = opcodes.OpClusterVerify()
977
    result = self.ExecOpCode(op)
978

    
979
    self.assertEqual(2, len(result["jobs"]))
980

    
981
  def testVerifyDefaultGroups(self):
982
    op = opcodes.OpClusterVerify(group_name="default")
983
    result = self.ExecOpCode(op)
984

    
985
    self.assertEqual(1, len(result["jobs"]))
986

    
987

    
988
class TestLUClusterVerifyConfig(CmdlibTestCase):
989

    
990
  def setUp(self):
991
    super(TestLUClusterVerifyConfig, self).setUp()
992

    
993
    self._load_cert_patcher = testutils \
994
      .patch_object(OpenSSL.crypto, "load_certificate")
995
    self._load_cert_mock = self._load_cert_patcher.start()
996
    self._verify_cert_patcher = testutils \
997
      .patch_object(utils, "VerifyX509Certificate")
998
    self._verify_cert_mock = self._verify_cert_patcher.start()
999
    self._read_file_patcher = testutils.patch_object(utils, "ReadFile")
1000
    self._read_file_mock = self._read_file_patcher.start()
1001
    self._can_read_patcher = testutils.patch_object(utils, "CanRead")
1002
    self._can_read_mock = self._can_read_patcher.start()
1003

    
1004
    self._can_read_mock.return_value = True
1005
    self._read_file_mock.return_value = True
1006
    self._verify_cert_mock.return_value = (None, "")
1007
    self._load_cert_mock.return_value = True
1008

    
1009
  def tearDown(self):
1010
    super(TestLUClusterVerifyConfig, self).tearDown()
1011

    
1012
    self._can_read_patcher.stop()
1013
    self._read_file_patcher.stop()
1014
    self._verify_cert_patcher.stop()
1015
    self._load_cert_patcher.stop()
1016

    
1017
  def testSuccessfulRun(self):
1018
    self.cfg.AddNewInstance()
1019
    op = opcodes.OpClusterVerifyConfig()
1020
    result = self.ExecOpCode(op)
1021

    
1022
    self.assertTrue(result)
1023

    
1024
  def testDanglingNode(self):
1025
    node = self.cfg.AddNewNode()
1026
    self.cfg.AddNewInstance(primary_node=node)
1027
    node.group = "invalid"
1028
    op = opcodes.OpClusterVerifyConfig()
1029
    result = self.ExecOpCode(op)
1030

    
1031
    self.mcpu.assertLogContainsRegex(
1032
      "following nodes \(and their instances\) belong to a non existing group")
1033
    self.assertFalse(result)
1034

    
1035
  def testDanglingInstance(self):
1036
    inst = self.cfg.AddNewInstance()
1037
    inst.primary_node = "invalid"
1038
    op = opcodes.OpClusterVerifyConfig()
1039
    result = self.ExecOpCode(op)
1040

    
1041
    self.mcpu.assertLogContainsRegex(
1042
      "following instances have a non-existing primary-node")
1043
    self.assertFalse(result)
1044

    
1045

    
1046
class TestLUClusterVerifyGroup(CmdlibTestCase):
1047
  def testEmptyNodeGroup(self):
1048
    group = self.cfg.AddNewNodeGroup()
1049
    op = opcodes.OpClusterVerifyGroup(group_name=group.name, verbose=True)
1050

    
1051
    result = self.ExecOpCode(op)
1052

    
1053
    self.assertTrue(result)
1054
    self.mcpu.assertLogContainsRegex("Empty node group, skipping verification")
1055

    
1056
  def testSimpleInvocation(self):
1057
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1058

    
1059
    self.ExecOpCode(op)
1060

    
1061
  def testSimpleInvocationWithInstance(self):
1062
    self.cfg.AddNewInstance(disks=[])
1063
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1064

    
1065
    self.ExecOpCode(op)
1066

    
1067
  def testGhostNode(self):
1068
    group = self.cfg.AddNewNodeGroup()
1069
    node = self.cfg.AddNewNode(group=group.uuid, offline=True)
1070
    self.master.offline = True
1071
    self.cfg.AddNewInstance(disk_template=constants.DT_DRBD8,
1072
                            primary_node=self.master,
1073
                            secondary_node=node)
1074

    
1075
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
1076
      RpcResultsBuilder() \
1077
        .AddOfflineNode(self.master) \
1078
        .Build()
1079

    
1080
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1081

    
1082
    self.ExecOpCode(op)
1083

    
1084
  def testValidRpcResult(self):
1085
    self.cfg.AddNewInstance(disks=[])
1086

    
1087
    self.rpc.call_node_verify.return_value = \
1088
      RpcResultsBuilder() \
1089
        .AddSuccessfulNode(self.master, {}) \
1090
        .Build()
1091

    
1092
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1093

    
1094
    self.ExecOpCode(op)
1095

    
1096

    
1097
class TestLUClusterVerifyGroupMethods(CmdlibTestCase):
1098
  """Base class for testing individual methods in LUClusterVerifyGroup.
1099

1100
  """
1101
  def setUp(self):
1102
    super(TestLUClusterVerifyGroupMethods, self).setUp()
1103
    self.op = opcodes.OpClusterVerifyGroup(group_name="default")
1104

    
1105
  def PrepareLU(self, lu):
1106
    lu._exclusive_storage = False
1107
    lu.master_node = self.master_uuid
1108
    lu.group_info = self.group
1109
    cluster.LUClusterVerifyGroup.all_node_info = \
1110
      property(fget=lambda _: self.cfg.GetAllNodesInfo())
1111

    
1112

    
1113
class TestLUClusterVerifyGroupVerifyNode(TestLUClusterVerifyGroupMethods):
1114
  @withLockedLU
1115
  def testInvalidNodeResult(self, lu):
1116
    self.assertFalse(lu._VerifyNode(self.master, None))
1117
    self.assertFalse(lu._VerifyNode(self.master, ""))
1118

    
1119
  @withLockedLU
1120
  def testInvalidVersion(self, lu):
1121
    self.assertFalse(lu._VerifyNode(self.master, {"version": None}))
1122
    self.assertFalse(lu._VerifyNode(self.master, {"version": ""}))
1123
    self.assertFalse(lu._VerifyNode(self.master, {
1124
      "version": (constants.PROTOCOL_VERSION - 1, constants.RELEASE_VERSION)
1125
    }))
1126

    
1127
    self.mcpu.ClearLogMessages()
1128
    self.assertTrue(lu._VerifyNode(self.master, {
1129
      "version": (constants.PROTOCOL_VERSION, constants.RELEASE_VERSION + "x")
1130
    }))
1131
    self.mcpu.assertLogContainsRegex("software version mismatch")
1132

    
1133
  def _GetValidNodeResult(self, additional_fields):
1134
    ret = {
1135
      "version": (constants.PROTOCOL_VERSION, constants.RELEASE_VERSION),
1136
      constants.NV_NODESETUP: []
1137
    }
1138
    ret.update(additional_fields)
1139
    return ret
1140

    
1141
  @withLockedLU
1142
  def testHypervisor(self, lu):
1143
    lu._VerifyNode(self.master, self._GetValidNodeResult({
1144
      constants.NV_HYPERVISOR: {
1145
        constants.HT_XEN_PVM: None,
1146
        constants.HT_XEN_HVM: "mock error"
1147
      }
1148
    }))
1149
    self.mcpu.assertLogContainsRegex(constants.HT_XEN_HVM)
1150
    self.mcpu.assertLogContainsRegex("mock error")
1151

    
1152
  @withLockedLU
1153
  def testHvParams(self, lu):
1154
    lu._VerifyNode(self.master, self._GetValidNodeResult({
1155
      constants.NV_HVPARAMS: [("mock item", constants.HT_XEN_HVM, "mock error")]
1156
    }))
1157
    self.mcpu.assertLogContainsRegex(constants.HT_XEN_HVM)
1158
    self.mcpu.assertLogContainsRegex("mock item")
1159
    self.mcpu.assertLogContainsRegex("mock error")
1160

    
1161
  @withLockedLU
1162
  def testSuccessfulResult(self, lu):
1163
    self.assertTrue(lu._VerifyNode(self.master, self._GetValidNodeResult({})))
1164
    self.mcpu.assertLogIsEmpty()
1165

    
1166

    
1167
class TestLUClusterVerifyGroupVerifyNodeTime(TestLUClusterVerifyGroupMethods):
1168
  @withLockedLU
1169
  def testInvalidNodeResult(self, lu):
1170
    for ndata in [{}, {constants.NV_TIME: "invalid"}]:
1171
      self.mcpu.ClearLogMessages()
1172
      lu._VerifyNodeTime(self.master, ndata, None, None)
1173

    
1174
      self.mcpu.assertLogContainsRegex("Node returned invalid time")
1175

    
1176
  @withLockedLU
1177
  def testNodeDiverges(self, lu):
1178
    for ntime in [(0, 0), (2000, 0)]:
1179
      self.mcpu.ClearLogMessages()
1180
      lu._VerifyNodeTime(self.master, {constants.NV_TIME: ntime}, 1000, 1005)
1181

    
1182
      self.mcpu.assertLogContainsRegex("Node time diverges")
1183

    
1184
  @withLockedLU
1185
  def testSuccessfulResult(self, lu):
1186
    lu._VerifyNodeTime(self.master, {constants.NV_TIME: (0, 0)}, 0, 5)
1187
    self.mcpu.assertLogIsEmpty()
1188

    
1189

    
1190
class TestLUClusterVerifyGroupUpdateVerifyNodeLVM(
1191
        TestLUClusterVerifyGroupMethods):
1192
  def setUp(self):
1193
    super(TestLUClusterVerifyGroupUpdateVerifyNodeLVM, self).setUp()
1194
    self.VALID_NRESULT = {
1195
      constants.NV_VGLIST: {"mock_vg": 30000},
1196
      constants.NV_PVLIST: [
1197
        {
1198
          "name": "mock_pv",
1199
          "vg_name": "mock_vg",
1200
          "size": 5000,
1201
          "free": 2500,
1202
          "attributes": [],
1203
          "lv_list": []
1204
        }
1205
      ]
1206
    }
1207

    
1208
  @withLockedLU
1209
  def testNoVgName(self, lu):
1210
    lu._UpdateVerifyNodeLVM(self.master, {}, None, None)
1211
    self.mcpu.assertLogIsEmpty()
1212

    
1213
  @withLockedLU
1214
  def testEmptyNodeResult(self, lu):
1215
    lu._UpdateVerifyNodeLVM(self.master, {}, "mock_vg", None)
1216
    self.mcpu.assertLogContainsRegex("unable to check volume groups")
1217
    self.mcpu.assertLogContainsRegex("Can't get PV list from node")
1218

    
1219
  @withLockedLU
1220
  def testValidNodeResult(self, lu):
1221
    lu._UpdateVerifyNodeLVM(self.master, self.VALID_NRESULT, "mock_vg", None)
1222
    self.mcpu.assertLogIsEmpty()
1223

    
1224
  @withLockedLU
1225
  def testValidNodeResultExclusiveStorage(self, lu):
1226
    lu._exclusive_storage = True
1227
    lu._UpdateVerifyNodeLVM(self.master, self.VALID_NRESULT, "mock_vg",
1228
                            cluster.LUClusterVerifyGroup.NodeImage())
1229
    self.mcpu.assertLogIsEmpty()
1230

    
1231

    
1232
class TestLUClusterVerifyGroupVerifyGroupDRBDVersion(
1233
        TestLUClusterVerifyGroupMethods):
1234
  @withLockedLU
1235
  def testEmptyNodeResult(self, lu):
1236
    lu._VerifyGroupDRBDVersion({})
1237
    self.mcpu.assertLogIsEmpty()
1238

    
1239
  @withLockedLU
1240
  def testValidNodeResult(self, lu):
1241
    lu._VerifyGroupDRBDVersion(
1242
      RpcResultsBuilder()
1243
        .AddSuccessfulNode(self.master, {
1244
          constants.NV_DRBDVERSION: "8.3.0"
1245
        })
1246
        .Build())
1247
    self.mcpu.assertLogIsEmpty()
1248

    
1249
  @withLockedLU
1250
  def testDifferentVersions(self, lu):
1251
    node1 = self.cfg.AddNewNode()
1252
    lu._VerifyGroupDRBDVersion(
1253
      RpcResultsBuilder()
1254
        .AddSuccessfulNode(self.master, {
1255
          constants.NV_DRBDVERSION: "8.3.0"
1256
        })
1257
        .AddSuccessfulNode(node1, {
1258
          constants.NV_DRBDVERSION: "8.4.0"
1259
        })
1260
        .Build())
1261
    self.mcpu.assertLogContainsRegex("DRBD version mismatch: 8.3.0")
1262
    self.mcpu.assertLogContainsRegex("DRBD version mismatch: 8.4.0")
1263

    
1264

    
1265
class TestLUClusterVerifyGroupVerifyGroupLVM(TestLUClusterVerifyGroupMethods):
1266
  @withLockedLU
1267
  def testNoVgName(self, lu):
1268
    lu._VerifyGroupLVM(None, None)
1269
    self.mcpu.assertLogIsEmpty()
1270

    
1271
  @withLockedLU
1272
  def testNoExclusiveStorage(self, lu):
1273
    lu._VerifyGroupLVM(None, "mock_vg")
1274
    self.mcpu.assertLogIsEmpty()
1275

    
1276
  @withLockedLU
1277
  def testNoPvInfo(self, lu):
1278
    lu._exclusive_storage = True
1279
    nimg = cluster.LUClusterVerifyGroup.NodeImage()
1280
    lu._VerifyGroupLVM({self.master.uuid: nimg}, "mock_vg")
1281
    self.mcpu.assertLogIsEmpty()
1282

    
1283
  @withLockedLU
1284
  def testValidPvInfos(self, lu):
1285
    lu._exclusive_storage = True
1286
    node2 = self.cfg.AddNewNode()
1287
    nimg1 = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master.uuid)
1288
    nimg1.pv_min = 10000
1289
    nimg1.pv_max = 10010
1290
    nimg2 = cluster.LUClusterVerifyGroup.NodeImage(uuid=node2.uuid)
1291
    nimg2.pv_min = 9998
1292
    nimg2.pv_max = 10005
1293
    lu._VerifyGroupLVM({self.master.uuid: nimg1, node2.uuid: nimg2}, "mock_vg")
1294
    self.mcpu.assertLogIsEmpty()
1295

    
1296

    
1297
class TestLUClusterVerifyGroupVerifyNodeBridges(
1298
        TestLUClusterVerifyGroupMethods):
1299
  @withLockedLU
1300
  def testNoBridges(self, lu):
1301
    lu._VerifyNodeBridges(None, None, None)
1302
    self.mcpu.assertLogIsEmpty()
1303

    
1304
  @withLockedLU
1305
  def testInvalidBridges(self, lu):
1306
    for ndata in [{}, {constants.NV_BRIDGES: ""}]:
1307
      self.mcpu.ClearLogMessages()
1308
      lu._VerifyNodeBridges(self.master, ndata, ["mock_bridge"])
1309
      self.mcpu.assertLogContainsRegex("not return valid bridge information")
1310

    
1311
    self.mcpu.ClearLogMessages()
1312
    lu._VerifyNodeBridges(self.master, {constants.NV_BRIDGES: ["mock_bridge"]},
1313
                          ["mock_bridge"])
1314
    self.mcpu.assertLogContainsRegex("missing bridge")
1315

    
1316

    
1317
class TestLUClusterVerifyGroupVerifyNodeUserScripts(
1318
        TestLUClusterVerifyGroupMethods):
1319
  @withLockedLU
1320
  def testNoUserScripts(self, lu):
1321
    lu._VerifyNodeUserScripts(self.master, {})
1322
    self.mcpu.assertLogContainsRegex("did not return user scripts information")
1323

    
1324
  @withLockedLU
1325
  def testBrokenUserScripts(self, lu):
1326
    lu._VerifyNodeUserScripts(self.master,
1327
                              {constants.NV_USERSCRIPTS: ["script"]})
1328
    self.mcpu.assertLogContainsRegex("scripts not present or not executable")
1329

    
1330

    
1331
class TestLUClusterVerifyGroupVerifyNodeNetwork(
1332
        TestLUClusterVerifyGroupMethods):
1333

    
1334
  def setUp(self):
1335
    super(TestLUClusterVerifyGroupVerifyNodeNetwork, self).setUp()
1336
    self.VALID_NRESULT = {
1337
      constants.NV_NODELIST: {},
1338
      constants.NV_NODENETTEST: {},
1339
      constants.NV_MASTERIP: True
1340
    }
1341

    
1342
  @withLockedLU
1343
  def testEmptyNodeResult(self, lu):
1344
    lu._VerifyNodeNetwork(self.master, {})
1345
    self.mcpu.assertLogContainsRegex(
1346
      "node hasn't returned node ssh connectivity data")
1347
    self.mcpu.assertLogContainsRegex(
1348
      "node hasn't returned node tcp connectivity data")
1349
    self.mcpu.assertLogContainsRegex(
1350
      "node hasn't returned node master IP reachability data")
1351

    
1352
  @withLockedLU
1353
  def testValidResult(self, lu):
1354
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1355
    self.mcpu.assertLogIsEmpty()
1356

    
1357
  @withLockedLU
1358
  def testSshProblem(self, lu):
1359
    self.VALID_NRESULT.update({
1360
      constants.NV_NODELIST: {
1361
        "mock_node": "mock_error"
1362
      }
1363
    })
1364
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1365
    self.mcpu.assertLogContainsRegex("ssh communication with node 'mock_node'")
1366

    
1367
  @withLockedLU
1368
  def testTcpProblem(self, lu):
1369
    self.VALID_NRESULT.update({
1370
      constants.NV_NODENETTEST: {
1371
        "mock_node": "mock_error"
1372
      }
1373
    })
1374
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1375
    self.mcpu.assertLogContainsRegex("tcp communication with node 'mock_node'")
1376

    
1377
  @withLockedLU
1378
  def testMasterIpNotReachable(self, lu):
1379
    self.VALID_NRESULT.update({
1380
      constants.NV_MASTERIP: False
1381
    })
1382
    node1 = self.cfg.AddNewNode()
1383
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1384
    self.mcpu.assertLogContainsRegex(
1385
      "the master node cannot reach the master IP")
1386

    
1387
    self.mcpu.ClearLogMessages()
1388
    lu._VerifyNodeNetwork(node1, self.VALID_NRESULT)
1389
    self.mcpu.assertLogContainsRegex("cannot reach the master IP")
1390

    
1391

    
1392
class TestLUClusterVerifyGroupVerifyInstance(TestLUClusterVerifyGroupMethods):
1393
  def setUp(self):
1394
    super(TestLUClusterVerifyGroupVerifyInstance, self).setUp()
1395

    
1396
    self.node1 = self.cfg.AddNewNode()
1397
    self.drbd_inst = self.cfg.AddNewInstance(
1398
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_DRBD8,
1399
                                 primary_node=self.master,
1400
                                 secondary_node=self.node1)])
1401
    self.running_inst = self.cfg.AddNewInstance(
1402
      admin_state=constants.ADMINST_UP, disks_active=True)
1403
    self.diskless_inst = self.cfg.AddNewInstance(disks=[])
1404

    
1405
    self.master_img = \
1406
      cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1407
    self.master_img.volumes = ["/".join(disk.logical_id)
1408
                               for inst in [self.running_inst,
1409
                                            self.diskless_inst]
1410
                               for disk in inst.disks]
1411
    self.master_img.volumes.extend(
1412
      ["/".join(disk.logical_id) for disk in self.drbd_inst.disks[0].children])
1413
    self.master_img.instances = [self.running_inst.uuid]
1414
    self.node1_img = \
1415
      cluster.LUClusterVerifyGroup.NodeImage(uuid=self.node1.uuid)
1416
    self.node1_img.volumes = \
1417
      ["/".join(disk.logical_id) for disk in self.drbd_inst.disks[0].children]
1418
    self.node_imgs = {
1419
      self.master_uuid: self.master_img,
1420
      self.node1.uuid: self.node1_img
1421
    }
1422
    self.diskstatus = {
1423
      self.master_uuid: [
1424
        (True, objects.BlockDevStatus(ldisk_status=constants.LDS_OKAY))
1425
        for _ in self.running_inst.disks
1426
      ]
1427
    }
1428

    
1429
  @withLockedLU
1430
  def testDisklessInst(self, lu):
1431
    lu._VerifyInstance(self.diskless_inst, self.node_imgs, {})
1432
    self.mcpu.assertLogIsEmpty()
1433

    
1434
  @withLockedLU
1435
  def testOfflineNode(self, lu):
1436
    self.master_img.offline = True
1437
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, {})
1438
    self.mcpu.assertLogIsEmpty()
1439

    
1440
  @withLockedLU
1441
  def testRunningOnOfflineNode(self, lu):
1442
    self.master_img.offline = True
1443
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1444
    self.mcpu.assertLogContainsRegex(
1445
      "instance is marked as running and lives on offline node")
1446

    
1447
  @withLockedLU
1448
  def testMissingVolume(self, lu):
1449
    self.master_img.volumes = []
1450
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1451
    self.mcpu.assertLogContainsRegex("volume .* missing")
1452

    
1453
  @withLockedLU
1454
  def testRunningInstanceOnWrongNode(self, lu):
1455
    self.master_img.instances = []
1456
    self.diskless_inst.admin_state = constants.ADMINST_UP
1457
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1458
    self.mcpu.assertLogContainsRegex("instance not running on its primary node")
1459

    
1460
  @withLockedLU
1461
  def testRunningInstanceOnRightNode(self, lu):
1462
    self.master_img.instances = [self.running_inst.uuid]
1463
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1464
    self.mcpu.assertLogIsEmpty()
1465

    
1466
  @withLockedLU
1467
  def testValidDiskStatus(self, lu):
1468
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1469
    self.mcpu.assertLogIsEmpty()
1470

    
1471
  @withLockedLU
1472
  def testDegradedDiskStatus(self, lu):
1473
    self.diskstatus[self.master_uuid][0][1].is_degraded = True
1474
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1475
    self.mcpu.assertLogContainsRegex("instance .* is degraded")
1476

    
1477
  @withLockedLU
1478
  def testNotOkayDiskStatus(self, lu):
1479
    self.diskstatus[self.master_uuid][0][1].ldisk_status = constants.LDS_FAULTY
1480
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1481
    self.mcpu.assertLogContainsRegex("instance .* state is 'faulty'")
1482

    
1483
  @withLockedLU
1484
  def testExclusiveStorageWithInvalidInstance(self, lu):
1485
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
1486
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1487
    self.mcpu.assertLogContainsRegex(
1488
      "instance has template drbd, which is not supported")
1489

    
1490
  @withLockedLU
1491
  def testExclusiveStorageWithValidInstance(self, lu):
1492
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
1493
    self.running_inst.disks[0].spindles = 1
1494
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1495
    self.mcpu.assertLogIsEmpty()
1496

    
1497
  @withLockedLU
1498
  def testDrbdInTwoGroups(self, lu):
1499
    group = self.cfg.AddNewNodeGroup()
1500
    self.node1.group = group.uuid
1501
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1502
    self.mcpu.assertLogContainsRegex(
1503
      "instance has primary and secondary nodes in different groups")
1504

    
1505
  @withLockedLU
1506
  def testOfflineSecondary(self, lu):
1507
    self.node1_img.offline = True
1508
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1509
    self.mcpu.assertLogContainsRegex("instance has offline secondary node\(s\)")
1510

    
1511

    
1512
class TestLUClusterVerifyGroupVerifyOrphanVolumes(
1513
        TestLUClusterVerifyGroupMethods):
1514
  @withLockedLU
1515
  def testOrphanedVolume(self, lu):
1516
    master_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1517
    master_img.volumes = ["mock_vg/disk_0", "mock_vg/disk_1", "mock_vg/disk_2"]
1518
    node_imgs = {
1519
      self.master_uuid: master_img
1520
    }
1521
    node_vol_should = {
1522
      self.master_uuid: ["mock_vg/disk_0"]
1523
    }
1524

    
1525
    lu._VerifyOrphanVolumes(node_vol_should, node_imgs,
1526
                            utils.FieldSet("mock_vg/disk_2"))
1527
    self.mcpu.assertLogContainsRegex("volume mock_vg/disk_1 is unknown")
1528
    self.mcpu.assertLogDoesNotContainRegex("volume mock_vg/disk_0 is unknown")
1529
    self.mcpu.assertLogDoesNotContainRegex("volume mock_vg/disk_2 is unknown")
1530

    
1531

    
1532
class TestLUClusterVerifyGroupVerifyNPlusOneMemory(
1533
        TestLUClusterVerifyGroupMethods):
1534
  @withLockedLU
1535
  def testN1Failure(self, lu):
1536
    group1 = self.cfg.AddNewNodeGroup()
1537

    
1538
    node1 = self.cfg.AddNewNode()
1539
    node2 = self.cfg.AddNewNode(group=group1)
1540
    node3 = self.cfg.AddNewNode()
1541

    
1542
    inst1 = self.cfg.AddNewInstance()
1543
    inst2 = self.cfg.AddNewInstance()
1544
    inst3 = self.cfg.AddNewInstance()
1545

    
1546
    node1_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node1.uuid)
1547
    node1_img.sbp = {
1548
      self.master_uuid: [inst1.uuid, inst2.uuid, inst3.uuid]
1549
    }
1550

    
1551
    node2_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node2.uuid)
1552

    
1553
    node3_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node3.uuid)
1554
    node3_img.offline = True
1555

    
1556
    node_imgs = {
1557
      node1.uuid: node1_img,
1558
      node2.uuid: node2_img,
1559
      node3.uuid: node3_img
1560
    }
1561

    
1562
    lu._VerifyNPlusOneMemory(node_imgs, self.cfg.GetAllInstancesInfo())
1563
    self.mcpu.assertLogContainsRegex(
1564
      "not enough memory to accomodate instance failovers")
1565

    
1566
    self.mcpu.ClearLogMessages()
1567
    node1_img.mfree = 1000
1568
    lu._VerifyNPlusOneMemory(node_imgs, self.cfg.GetAllInstancesInfo())
1569
    self.mcpu.assertLogIsEmpty()
1570

    
1571

    
1572
class TestLUClusterVerifyGroupVerifyFiles(TestLUClusterVerifyGroupMethods):
1573
  @withLockedLU
1574
  def test(self, lu):
1575
    node1 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1576
                                vm_capable=True)
1577
    node2 = self.cfg.AddNewNode(master_candidate=True, vm_capable=False)
1578
    node3 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1579
                                vm_capable=True)
1580
    node4 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1581
                                vm_capable=True)
1582
    node5 = self.cfg.AddNewNode(master_candidate=False, offline=True)
1583

    
1584
    nodeinfo = [self.master, node1, node2, node3, node4, node5]
1585
    files_all = set([
1586
      pathutils.CLUSTER_DOMAIN_SECRET_FILE,
1587
      pathutils.RAPI_CERT_FILE,
1588
      pathutils.RAPI_USERS_FILE,
1589
      ])
1590
    files_opt = set([
1591
      pathutils.RAPI_USERS_FILE,
1592
      hv_xen.XL_CONFIG_FILE,
1593
      pathutils.VNC_PASSWORD_FILE,
1594
      ])
1595
    files_mc = set([
1596
      pathutils.CLUSTER_CONF_FILE,
1597
      ])
1598
    files_vm = set([
1599
      hv_xen.XEND_CONFIG_FILE,
1600
      hv_xen.XL_CONFIG_FILE,
1601
      pathutils.VNC_PASSWORD_FILE,
1602
      ])
1603
    nvinfo = RpcResultsBuilder() \
1604
      .AddSuccessfulNode(self.master, {
1605
        constants.NV_FILELIST: {
1606
          pathutils.CLUSTER_CONF_FILE: "82314f897f38b35f9dab2f7c6b1593e0",
1607
          pathutils.RAPI_CERT_FILE: "babbce8f387bc082228e544a2146fee4",
1608
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1609
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
1610
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
1611
        }}) \
1612
      .AddSuccessfulNode(node1, {
1613
        constants.NV_FILELIST: {
1614
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1615
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
1616
          }
1617
        }) \
1618
      .AddSuccessfulNode(node2, {
1619
        constants.NV_FILELIST: {
1620
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1621
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1622
          }
1623
        }) \
1624
      .AddSuccessfulNode(node3, {
1625
        constants.NV_FILELIST: {
1626
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1627
          pathutils.CLUSTER_CONF_FILE: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
1628
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1629
          pathutils.RAPI_USERS_FILE: "rapiusers-ea3271e8d810ef3",
1630
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
1631
          }
1632
        }) \
1633
      .AddSuccessfulNode(node4, {}) \
1634
      .AddOfflineNode(node5) \
1635
      .Build()
1636
    assert set(nvinfo.keys()) == set(map(operator.attrgetter("uuid"), nodeinfo))
1637

    
1638
    lu._VerifyFiles(nodeinfo, self.master_uuid, nvinfo,
1639
                    (files_all, files_opt, files_mc, files_vm))
1640

    
1641
    expected_msgs = [
1642
      "File %s found with 2 different checksums (variant 1 on"
1643
        " %s, %s, %s; variant 2 on %s)" %
1644
        (pathutils.RAPI_CERT_FILE, node1.name, node2.name, node3.name,
1645
         self.master.name),
1646
      "File %s is missing from node(s) %s" %
1647
        (pathutils.CLUSTER_DOMAIN_SECRET_FILE, node1.name),
1648
      "File %s should not exist on node(s) %s" %
1649
        (pathutils.CLUSTER_CONF_FILE, node3.name),
1650
      "File %s is missing from node(s) %s" %
1651
        (hv_xen.XEND_CONFIG_FILE, node3.name),
1652
      "File %s is missing from node(s) %s" %
1653
        (pathutils.CLUSTER_CONF_FILE, node2.name),
1654
      "File %s found with 2 different checksums (variant 1 on"
1655
        " %s; variant 2 on %s)" %
1656
        (pathutils.CLUSTER_CONF_FILE, self.master.name, node3.name),
1657
      "File %s is optional, but it must exist on all or no nodes (not"
1658
        " found on %s, %s, %s)" %
1659
        (pathutils.RAPI_USERS_FILE, self.master.name, node1.name, node2.name),
1660
      "File %s is optional, but it must exist on all or no nodes (not"
1661
        " found on %s)" % (hv_xen.XL_CONFIG_FILE, node1.name),
1662
      "Node did not return file checksum data",
1663
      ]
1664

    
1665
    self.assertEqual(len(self.mcpu.GetLogMessages()), len(expected_msgs))
1666
    for expected_msg in expected_msgs:
1667
      self.mcpu.assertLogContainsInLine(expected_msg)
1668

    
1669

    
1670
class TestLUClusterVerifyGroupVerifyNodeDrbd(TestLUClusterVerifyGroupMethods):
1671
  def setUp(self):
1672
    super(TestLUClusterVerifyGroupVerifyNodeDrbd, self).setUp()
1673

    
1674
    self.node1 = self.cfg.AddNewNode()
1675
    self.node2 = self.cfg.AddNewNode()
1676
    self.inst = self.cfg.AddNewInstance(
1677
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_DRBD8,
1678
                                 primary_node=self.node1,
1679
                                 secondary_node=self.node2)],
1680
      admin_state=constants.ADMINST_UP)
1681

    
1682
  @withLockedLU
1683
  def testNoDrbdHelper(self, lu):
1684
    lu._VerifyNodeDrbd(self.master, {}, self.cfg.GetAllInstancesInfo(), None,
1685
                       self.cfg.ComputeDRBDMap())
1686
    self.mcpu.assertLogIsEmpty()
1687

    
1688
  @withLockedLU
1689
  def testDrbdHelperInvalidNodeResult(self, lu):
1690
    for ndata, expected in [({}, "no drbd usermode helper returned"),
1691
                            ({constants.NV_DRBDHELPER: (False, "")},
1692
                             "drbd usermode helper check unsuccessful"),
1693
                            ({constants.NV_DRBDHELPER: (True, "/bin/false")},
1694
                             "wrong drbd usermode helper")]:
1695
      self.mcpu.ClearLogMessages()
1696
      lu._VerifyNodeDrbd(self.master, ndata, self.cfg.GetAllInstancesInfo(),
1697
                         "/bin/true", self.cfg.ComputeDRBDMap())
1698
      self.mcpu.assertLogContainsRegex(expected)
1699

    
1700
  @withLockedLU
1701
  def testNoNodeResult(self, lu):
1702
    lu._VerifyNodeDrbd(self.node1, {}, self.cfg.GetAllInstancesInfo(),
1703
                         None, self.cfg.ComputeDRBDMap())
1704
    self.mcpu.assertLogContainsRegex("drbd minor 1 of .* is not active")
1705

    
1706
  @withLockedLU
1707
  def testInvalidNodeResult(self, lu):
1708
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: ""},
1709
                       self.cfg.GetAllInstancesInfo(), None,
1710
                       self.cfg.ComputeDRBDMap())
1711
    self.mcpu.assertLogContainsRegex("cannot parse drbd status file")
1712

    
1713
  @withLockedLU
1714
  def testWrongMinorInUse(self, lu):
1715
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: [2]},
1716
                       self.cfg.GetAllInstancesInfo(), None,
1717
                       self.cfg.ComputeDRBDMap())
1718
    self.mcpu.assertLogContainsRegex("drbd minor 1 of .* is not active")
1719
    self.mcpu.assertLogContainsRegex("unallocated drbd minor 2 is in use")
1720

    
1721
  @withLockedLU
1722
  def testValidResult(self, lu):
1723
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: [1]},
1724
                       self.cfg.GetAllInstancesInfo(), None,
1725
                       self.cfg.ComputeDRBDMap())
1726
    self.mcpu.assertLogIsEmpty()
1727

    
1728

    
1729
class TestLUClusterVerifyGroupVerifyNodeOs(TestLUClusterVerifyGroupMethods):
1730
  @withLockedLU
1731
  def testUpdateNodeOsInvalidNodeResult(self, lu):
1732
    for ndata in [{}, {constants.NV_OSLIST: ""}, {constants.NV_OSLIST: [""]},
1733
                  {constants.NV_OSLIST: [["1", "2"]]}]:
1734
      self.mcpu.ClearLogMessages()
1735
      nimage = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1736
      lu._UpdateNodeOS(self.master, ndata, nimage)
1737
      self.mcpu.assertLogContainsRegex("node hasn't returned valid OS data")
1738

    
1739
  @withLockedLU
1740
  def testUpdateNodeOsValidNodeResult(self, lu):
1741
    ndata = {
1742
      constants.NV_OSLIST: [
1743
        ["mock_OS", "/mocked/path", True, "", ["default"], [],
1744
         [constants.OS_API_V20]],
1745
        ["Another_Mock", "/random", True, "", ["var1", "var2"],
1746
         [{"param1": "val1"}, {"param2": "val2"}], constants.OS_API_VERSIONS]
1747
      ]
1748
    }
1749
    nimage = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1750
    lu._UpdateNodeOS(self.master, ndata, nimage)
1751
    self.mcpu.assertLogIsEmpty()
1752

    
1753
  @withLockedLU
1754
  def testVerifyNodeOs(self, lu):
1755
    node = self.cfg.AddNewNode()
1756
    nimg_root = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1757
    nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=node.uuid)
1758

    
1759
    nimg_root.os_fail = False
1760
    nimg_root.oslist = {
1761
      "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1762
                   set([constants.OS_API_V20]))],
1763
      "broken_base_os": [("/broken", False, "", set(), set(),
1764
                         set([constants.OS_API_V20]))],
1765
      "only_on_root": [("/random", True, "", set(), set(), set())],
1766
      "diffing_os": [("/pinky", True, "", set(["var1", "var2"]),
1767
                      set([("param1", "val1"), ("param2", "val2")]),
1768
                      set([constants.OS_API_V20]))]
1769
    }
1770
    nimg.os_fail = False
1771
    nimg.oslist = {
1772
      "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1773
                   set([constants.OS_API_V20]))],
1774
      "only_on_test": [("/random", True, "", set(), set(), set())],
1775
      "diffing_os": [("/bunny", True, "", set(["var1", "var3"]),
1776
                      set([("param1", "val1"), ("param3", "val3")]),
1777
                      set([constants.OS_API_V15]))],
1778
      "broken_os": [("/broken", False, "", set(), set(),
1779
                     set([constants.OS_API_V20]))],
1780
      "multi_entries": [
1781
        ("/multi1", True, "", set(), set(), set([constants.OS_API_V20])),
1782
        ("/multi2", True, "", set(), set(), set([constants.OS_API_V20]))]
1783
    }
1784

    
1785
    lu._VerifyNodeOS(node, nimg, nimg_root)
1786

    
1787
    expected_msgs = [
1788
      "Extra OS only_on_test not present on reference node",
1789
      "OSes present on reference node .* but missing on this node:" +
1790
        " only_on_root",
1791
      "OS API version for diffing_os differs",
1792
      "OS variants list for diffing_os differs",
1793
      "OS parameters for diffing_os differs",
1794
      "Invalid OS broken_os",
1795
      "Extra OS broken_os not present on reference node",
1796
      "OS 'multi_entries' has multiple entries",
1797
      "Extra OS multi_entries not present on reference node"
1798
    ]
1799

    
1800
    self.assertEqual(len(expected_msgs), len(self.mcpu.GetLogMessages()))
1801
    for expected_msg in expected_msgs:
1802
      self.mcpu.assertLogContainsRegex(expected_msg)
1803

    
1804

    
1805
class TestLUClusterVerifyGroupVerifyAcceptedFileStoragePaths(
1806
  TestLUClusterVerifyGroupMethods):
1807
  @withLockedLU
1808
  def testNotMaster(self, lu):
1809
    lu._VerifyAcceptedFileStoragePaths(self.master, {}, False)
1810
    self.mcpu.assertLogIsEmpty()
1811

    
1812
  @withLockedLU
1813
  def testNotMasterButRetunedValue(self, lu):
1814
    lu._VerifyAcceptedFileStoragePaths(
1815
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: []}, False)
1816
    self.mcpu.assertLogContainsRegex(
1817
      "Node should not have returned forbidden file storage paths")
1818

    
1819
  @withLockedLU
1820
  def testMasterInvalidNodeResult(self, lu):
1821
    lu._VerifyAcceptedFileStoragePaths(self.master, {}, True)
1822
    self.mcpu.assertLogContainsRegex(
1823
      "Node did not return forbidden file storage paths")
1824

    
1825
  @withLockedLU
1826
  def testMasterForbiddenPaths(self, lu):
1827
    lu._VerifyAcceptedFileStoragePaths(
1828
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: ["/forbidden"]}, True)
1829
    self.mcpu.assertLogContainsRegex("Found forbidden file storage paths")
1830

    
1831
  @withLockedLU
1832
  def testMasterSuccess(self, lu):
1833
    lu._VerifyAcceptedFileStoragePaths(
1834
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: []}, True)
1835
    self.mcpu.assertLogIsEmpty()
1836

    
1837

    
1838
class TestLUClusterVerifyGroupVerifyStoragePaths(
1839
  TestLUClusterVerifyGroupMethods):
1840
  @withLockedLU
1841
  def testVerifyFileStoragePathsSuccess(self, lu):
1842
    lu._VerifyFileStoragePaths(self.master, {})
1843
    self.mcpu.assertLogIsEmpty()
1844

    
1845
  @withLockedLU
1846
  def testVerifyFileStoragePathsFailure(self, lu):
1847
    lu._VerifyFileStoragePaths(self.master,
1848
                               {constants.NV_FILE_STORAGE_PATH: "/fail/path"})
1849
    self.mcpu.assertLogContainsRegex(
1850
      "The configured file storage path is unusable")
1851

    
1852
  @withLockedLU
1853
  def testVerifySharedFileStoragePathsSuccess(self, lu):
1854
    lu._VerifySharedFileStoragePaths(self.master, {})
1855
    self.mcpu.assertLogIsEmpty()
1856

    
1857
  @withLockedLU
1858
  def testVerifySharedFileStoragePathsFailure(self, lu):
1859
    lu._VerifySharedFileStoragePaths(
1860
      self.master, {constants.NV_SHARED_FILE_STORAGE_PATH: "/fail/path"})
1861
    self.mcpu.assertLogContainsRegex(
1862
      "The configured sharedfile storage path is unusable")
1863

    
1864

    
1865
class TestLUClusterVerifyGroupVerifyOob(TestLUClusterVerifyGroupMethods):
1866
  @withLockedLU
1867
  def testEmptyResult(self, lu):
1868
    lu._VerifyOob(self.master, {})
1869
    self.mcpu.assertLogIsEmpty()
1870

    
1871
  @withLockedLU
1872
  def testErrorResults(self, lu):
1873
    lu._VerifyOob(self.master, {constants.NV_OOB_PATHS: ["path1", "path2"]})
1874
    self.mcpu.assertLogContainsRegex("path1")
1875
    self.mcpu.assertLogContainsRegex("path2")
1876

    
1877

    
1878
class TestLUClusterVerifyGroupUpdateNodeVolumes(
1879
  TestLUClusterVerifyGroupMethods):
1880
  def setUp(self):
1881
    super(TestLUClusterVerifyGroupUpdateNodeVolumes, self).setUp()
1882
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1883

    
1884
  @withLockedLU
1885
  def testNoVgName(self, lu):
1886
    lu._UpdateNodeVolumes(self.master, {}, self.nimg, None)
1887
    self.mcpu.assertLogIsEmpty()
1888
    self.assertTrue(self.nimg.lvm_fail)
1889

    
1890
  @withLockedLU
1891
  def testErrorMessage(self, lu):
1892
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: "mock error"},
1893
                          self.nimg, "mock_vg")
1894
    self.mcpu.assertLogContainsRegex("LVM problem on node: mock error")
1895
    self.assertTrue(self.nimg.lvm_fail)
1896

    
1897
  @withLockedLU
1898
  def testInvalidNodeResult(self, lu):
1899
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: [1, 2, 3]},
1900
                          self.nimg, "mock_vg")
1901
    self.mcpu.assertLogContainsRegex("rpc call to node failed")
1902
    self.assertTrue(self.nimg.lvm_fail)
1903

    
1904
  @withLockedLU
1905
  def testValidNodeResult(self, lu):
1906
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: {}},
1907
                          self.nimg, "mock_vg")
1908
    self.mcpu.assertLogIsEmpty()
1909
    self.assertFalse(self.nimg.lvm_fail)
1910

    
1911

    
1912
class TestLUClusterVerifyGroupUpdateNodeInstances(
1913
  TestLUClusterVerifyGroupMethods):
1914
  def setUp(self):
1915
    super(TestLUClusterVerifyGroupUpdateNodeInstances, self).setUp()
1916
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1917

    
1918
  @withLockedLU
1919
  def testInvalidNodeResult(self, lu):
1920
    lu._UpdateNodeInstances(self.master, {}, self.nimg)
1921
    self.mcpu.assertLogContainsRegex("rpc call to node failed")
1922

    
1923
  @withLockedLU
1924
  def testValidNodeResult(self, lu):
1925
    inst = self.cfg.AddNewInstance()
1926
    lu._UpdateNodeInstances(self.master,
1927
                            {constants.NV_INSTANCELIST: [inst.name]},
1928
                            self.nimg)
1929
    self.mcpu.assertLogIsEmpty()
1930

    
1931

    
1932
class TestLUClusterVerifyGroupUpdateNodeInfo(TestLUClusterVerifyGroupMethods):
1933
  def setUp(self):
1934
    super(TestLUClusterVerifyGroupUpdateNodeInfo, self).setUp()
1935
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1936
    self.valid_hvresult = {constants.NV_HVINFO: {"memory_free": 1024}}
1937

    
1938
  @withLockedLU
1939
  def testInvalidHvNodeResult(self, lu):
1940
    for ndata in [{}, {constants.NV_HVINFO: ""}]:
1941
      self.mcpu.ClearLogMessages()
1942
      lu._UpdateNodeInfo(self.master, ndata, self.nimg, None)
1943
      self.mcpu.assertLogContainsRegex("rpc call to node failed")
1944

    
1945
  @withLockedLU
1946
  def testInvalidMemoryFreeHvNodeResult(self, lu):
1947
    lu._UpdateNodeInfo(self.master,
1948
                       {constants.NV_HVINFO: {"memory_free": "abc"}},
1949
                       self.nimg, None)
1950
    self.mcpu.assertLogContainsRegex(
1951
      "node returned invalid nodeinfo, check hypervisor")
1952

    
1953
  @withLockedLU
1954
  def testValidHvNodeResult(self, lu):
1955
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, None)
1956
    self.mcpu.assertLogIsEmpty()
1957

    
1958
  @withLockedLU
1959
  def testInvalidVgNodeResult(self, lu):
1960
    for vgdata in [[], ""]:
1961
      self.mcpu.ClearLogMessages()
1962
      ndata = {constants.NV_VGLIST: vgdata}
1963
      ndata.update(self.valid_hvresult)
1964
      lu._UpdateNodeInfo(self.master, ndata, self.nimg, "mock_vg")
1965
      self.mcpu.assertLogContainsRegex(
1966
        "node didn't return data for the volume group 'mock_vg'")
1967

    
1968
  @withLockedLU
1969
  def testInvalidDiskFreeVgNodeResult(self, lu):
1970
    self.valid_hvresult.update({
1971
      constants.NV_VGLIST: {"mock_vg": "abc"}
1972
    })
1973
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, "mock_vg")
1974
    self.mcpu.assertLogContainsRegex(
1975
      "node returned invalid LVM info, check LVM status")
1976

    
1977
  @withLockedLU
1978
  def testValidVgNodeResult(self, lu):
1979
    self.valid_hvresult.update({
1980
      constants.NV_VGLIST: {"mock_vg": 10000}
1981
    })
1982
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, "mock_vg")
1983
    self.mcpu.assertLogIsEmpty()
1984

    
1985

    
1986
class TestLUClusterVerifyGroupCollectDiskInfo(TestLUClusterVerifyGroupMethods):
1987
  def setUp(self):
1988
    super(TestLUClusterVerifyGroupCollectDiskInfo, self).setUp()
1989

    
1990
    self.node1 = self.cfg.AddNewNode()
1991
    self.node2 = self.cfg.AddNewNode()
1992
    self.node3 = self.cfg.AddNewNode()
1993

    
1994
    self.diskless_inst = \
1995
      self.cfg.AddNewInstance(primary_node=self.node1,
1996
                              disk_template=constants.DT_DISKLESS)
1997
    self.plain_inst = \
1998
      self.cfg.AddNewInstance(primary_node=self.node2,
1999
                              disk_template=constants.DT_PLAIN)
2000
    self.drbd_inst = \
2001
      self.cfg.AddNewInstance(primary_node=self.node3,
2002
                              secondary_node=self.node2,
2003
                              disk_template=constants.DT_DRBD8)
2004

    
2005
    self.node1_img = cluster.LUClusterVerifyGroup.NodeImage(
2006
                       uuid=self.node1.uuid)
2007
    self.node1_img.pinst = [self.diskless_inst.uuid]
2008
    self.node1_img.sinst = []
2009
    self.node2_img = cluster.LUClusterVerifyGroup.NodeImage(
2010
                       uuid=self.node2.uuid)
2011
    self.node2_img.pinst = [self.plain_inst.uuid]
2012
    self.node2_img.sinst = [self.drbd_inst.uuid]
2013
    self.node3_img = cluster.LUClusterVerifyGroup.NodeImage(
2014
                       uuid=self.node3.uuid)
2015
    self.node3_img.pinst = [self.drbd_inst.uuid]
2016
    self.node3_img.sinst = []
2017

    
2018
    self.node_images = {
2019
      self.node1.uuid: self.node1_img,
2020
      self.node2.uuid: self.node2_img,
2021
      self.node3.uuid: self.node3_img
2022
    }
2023

    
2024
    self.node_uuids = [self.node1.uuid, self.node2.uuid, self.node3.uuid]
2025

    
2026
  @withLockedLU
2027
  def testSuccessfulRun(self, lu):
2028
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
2029
      RpcResultsBuilder() \
2030
        .AddSuccessfulNode(self.node2, [(True, ""), (True, "")]) \
2031
        .AddSuccessfulNode(self.node3, [(True, "")]) \
2032
        .Build()
2033

    
2034
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
2035
                        self.cfg.GetAllInstancesInfo())
2036

    
2037
    self.mcpu.assertLogIsEmpty()
2038

    
2039
  @withLockedLU
2040
  def testOfflineAndFailingNodes(self, lu):
2041
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
2042
      RpcResultsBuilder() \
2043
        .AddOfflineNode(self.node2) \
2044
        .AddFailedNode(self.node3) \
2045
        .Build()
2046

    
2047
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
2048
                        self.cfg.GetAllInstancesInfo())
2049

    
2050
    self.mcpu.assertLogContainsRegex("while getting disk information")
2051

    
2052
  @withLockedLU
2053
  def testInvalidNodeResult(self, lu):
2054
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
2055
      RpcResultsBuilder() \
2056
        .AddSuccessfulNode(self.node2, [(True,), (False,)]) \
2057
        .AddSuccessfulNode(self.node3, [""]) \
2058
        .Build()
2059

    
2060
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
2061
                        self.cfg.GetAllInstancesInfo())
2062
    # logging is not performed through mcpu
2063
    self.mcpu.assertLogIsEmpty()
2064

    
2065

    
2066
class TestLUClusterVerifyGroupHooksCallBack(TestLUClusterVerifyGroupMethods):
2067
  def setUp(self):
2068
    super(TestLUClusterVerifyGroupHooksCallBack, self).setUp()
2069

    
2070
    self.feedback_fn = lambda _: None
2071

    
2072
  def PrepareLU(self, lu):
2073
    super(TestLUClusterVerifyGroupHooksCallBack, self).PrepareLU(lu)
2074

    
2075
    lu.my_node_uuids = list(self.cfg.GetAllNodesInfo().keys())
2076

    
2077
  @withLockedLU
2078
  def testEmptyGroup(self, lu):
2079
    lu.my_node_uuids = []
2080
    lu.HooksCallBack(constants.HOOKS_PHASE_POST, None, self.feedback_fn, None)
2081

    
2082
  @withLockedLU
2083
  def testFailedResult(self, lu):
2084
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2085
                     RpcResultsBuilder(use_node_names=True)
2086
                       .AddFailedNode(self.master).Build(),
2087
                     self.feedback_fn,
2088
                     None)
2089
    self.mcpu.assertLogContainsRegex("Communication failure in hooks execution")
2090

    
2091
  @withLockedLU
2092
  def testOfflineNode(self, lu):
2093
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2094
                     RpcResultsBuilder(use_node_names=True)
2095
                       .AddOfflineNode(self.master).Build(),
2096
                     self.feedback_fn,
2097
                     None)
2098

    
2099
  @withLockedLU
2100
  def testValidResult(self, lu):
2101
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2102
                     RpcResultsBuilder(use_node_names=True)
2103
                       .AddSuccessfulNode(self.master,
2104
                                          [("mock_script",
2105
                                            constants.HKR_SUCCESS,
2106
                                            "mock output")])
2107
                       .Build(),
2108
                     self.feedback_fn,
2109
                     None)
2110

    
2111
  @withLockedLU
2112
  def testFailedScriptResult(self, lu):
2113
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2114
                     RpcResultsBuilder(use_node_names=True)
2115
                       .AddSuccessfulNode(self.master,
2116
                                          [("mock_script",
2117
                                            constants.HKR_FAIL,
2118
                                            "mock output")])
2119
                       .Build(),
2120
                     self.feedback_fn,
2121
                     None)
2122
    self.mcpu.assertLogContainsRegex("Script mock_script failed")
2123

    
2124

    
2125
class TestLUClusterVerifyDisks(CmdlibTestCase):
2126
  def testVerifyDisks(self):
2127
    op = opcodes.OpClusterVerifyDisks()
2128
    result = self.ExecOpCode(op)
2129

    
2130
    self.assertEqual(1, len(result["jobs"]))
2131

    
2132

    
2133
if __name__ == "__main__":
2134
  testutils.GanetiTestProgram()