Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / cluster_unittest.py @ 5b6f9e35

History | View | Annotate | Download (75.8 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 collections import defaultdict
35

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

    
47
from testsupport import *
48

    
49
import testutils
50

    
51

    
52
class TestCertVerification(testutils.GanetiTestCase):
53
  def setUp(self):
54
    testutils.GanetiTestCase.setUp(self)
55

    
56
    self.tmpdir = tempfile.mkdtemp()
57

    
58
  def tearDown(self):
59
    shutil.rmtree(self.tmpdir)
60

    
61
  def testVerifyCertificate(self):
62
    cluster._VerifyCertificate(testutils.TestDataFilename("cert1.pem"))
63

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

    
66
    (errcode, msg) = cluster._VerifyCertificate(nonexist_filename)
67
    self.assertEqual(errcode, cluster.LUClusterVerifyConfig.ETYPE_ERROR)
68

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

    
74

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

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

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

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

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

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

    
133

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

    
138
    self.rpc.call_node_activate_master_ip.return_value = \
139
      self.RpcResultsBuilder() \
140
        .CreateSuccessfulNodeResult(self.master)
141

    
142
    self.ExecOpCode(op)
143

    
144
    self.rpc.call_node_activate_master_ip.assert_called_once_with(
145
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
146

    
147
  def testFailure(self):
148
    op = opcodes.OpClusterActivateMasterIp()
149

    
150
    self.rpc.call_node_activate_master_ip.return_value = \
151
      self.RpcResultsBuilder() \
152
        .CreateFailedNodeResult(self.master) \
153

    
154
    self.ExecOpCodeExpectOpExecError(op)
155

    
156

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

    
161
    self.rpc.call_node_deactivate_master_ip.return_value = \
162
      self.RpcResultsBuilder() \
163
        .CreateSuccessfulNodeResult(self.master)
164

    
165
    self.ExecOpCode(op)
166

    
167
    self.rpc.call_node_deactivate_master_ip.assert_called_once_with(
168
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
169

    
170
  def testFailure(self):
171
    op = opcodes.OpClusterDeactivateMasterIp()
172

    
173
    self.rpc.call_node_deactivate_master_ip.return_value = \
174
      self.RpcResultsBuilder() \
175
        .CreateFailedNodeResult(self.master) \
176

    
177
    self.ExecOpCodeExpectOpExecError(op)
178

    
179

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

    
184
    self.ExecOpCodeExpectOpPrereqError(op, "pinky_bunny")
185

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

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

    
193
    ret = self.ExecOpCode(op)
194

    
195
    self.assertEqual(1, self.rpc.call_get_watcher_pause.call_count)
196
    self.assertEqual(len(ret), len(query.CLUSTER_FIELDS))
197

    
198
  def testEmpytFields(self):
199
    op = opcodes.OpClusterConfigQuery(output_fields=[])
200

    
201
    self.ExecOpCode(op)
202

    
203
    self.assertFalse(self.rpc.call_get_watcher_pause.called)
204

    
205

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

    
210
    self.cfg.AddNewNode()
211
    self.cfg.AddNewNode()
212

    
213
    self.ExecOpCodeExpectOpPrereqError(op, "still 2 node\(s\)")
214

    
215
  def testExistingInstances(self):
216
    op = opcodes.OpClusterDestroy()
217

    
218
    self.cfg.AddNewInstance()
219
    self.cfg.AddNewInstance()
220

    
221
    self.ExecOpCodeExpectOpPrereqError(op, "still 2 instance\(s\)")
222

    
223
  def testEmptyCluster(self):
224
    op = opcodes.OpClusterDestroy()
225

    
226
    self.ExecOpCode(op)
227

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

    
232

    
233
class TestLUClusterPostInit(CmdlibTestCase):
234
  def testExecution(self):
235
    # For the purpose of this test, return the same certificate digest for all
236
    # nodes
237
    self.rpc.call_node_crypto_tokens = \
238
      lambda node_uuid, _: self.RpcResultsBuilder() \
239
        .CreateSuccessfulNodeResult(node_uuid,
240
          [(constants.CRYPTO_TYPE_SSL_DIGEST, "IA:MA:FA:KE:DI:GE:ST")])
241
    op = opcodes.OpClusterPostInit()
242

    
243
    self.ExecOpCode(op)
244

    
245
    self.assertSingleHooksCall([self.master.name],
246
                               "cluster-init",
247
                               constants.HOOKS_PHASE_POST)
248

    
249

    
250
class TestLUClusterQuery(CmdlibTestCase):
251
  def testSimpleInvocation(self):
252
    op = opcodes.OpClusterQuery()
253

    
254
    self.ExecOpCode(op)
255

    
256
  def testIPv6Cluster(self):
257
    op = opcodes.OpClusterQuery()
258

    
259
    self.cluster.primary_ip_family = netutils.IP6Address.family
260

    
261
    self.ExecOpCode(op)
262

    
263

    
264
class TestLUClusterRedistConf(CmdlibTestCase):
265
  def testSimpleInvocation(self):
266
    op = opcodes.OpClusterRedistConf()
267

    
268
    self.ExecOpCode(op)
269

    
270

    
271
class TestLUClusterRename(CmdlibTestCase):
272
  NEW_NAME = "new-name.example.com"
273
  NEW_IP = "203.0.113.100"
274

    
275
  def testNoChanges(self):
276
    op = opcodes.OpClusterRename(name=self.cfg.GetClusterName())
277

    
278
    self.ExecOpCodeExpectOpPrereqError(op, "name nor the IP address")
279

    
280
  def testReachableIp(self):
281
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
282

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

    
287
    self.ExecOpCodeExpectOpPrereqError(op, "is reachable on the network")
288

    
289
  def testValidRename(self):
290
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
291

    
292
    self.netutils_mod.GetHostname.return_value = \
293
      HostnameMock(self.NEW_NAME, self.NEW_IP)
294

    
295
    self.ExecOpCode(op)
296

    
297
    self.assertEqual(1, self.ssh_mod.WriteKnownHostsFile.call_count)
298
    self.rpc.call_node_deactivate_master_ip.assert_called_once_with(
299
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
300
    self.rpc.call_node_activate_master_ip.assert_called_once_with(
301
      self.master_uuid, self.cfg.GetMasterNetworkParameters(), False)
302

    
303
  def testRenameOfflineMaster(self):
304
    op = opcodes.OpClusterRename(name=self.NEW_NAME)
305

    
306
    self.master.offline = True
307
    self.netutils_mod.GetHostname.return_value = \
308
      HostnameMock(self.NEW_NAME, self.NEW_IP)
309

    
310
    self.ExecOpCode(op)
311

    
312

    
313
class TestLUClusterRepairDiskSizes(CmdlibTestCase):
314
  def testNoInstances(self):
315
    op = opcodes.OpClusterRepairDiskSizes()
316

    
317
    self.ExecOpCode(op)
318

    
319
  def _SetUpInstanceSingleDisk(self, dev_type=constants.DT_PLAIN):
320
    pnode = self.master
321
    snode = self.cfg.AddNewNode()
322

    
323
    disk = self.cfg.CreateDisk(dev_type=dev_type,
324
                               primary_node=pnode,
325
                               secondary_node=snode)
326
    inst = self.cfg.AddNewInstance(disks=[disk])
327

    
328
    return (inst, disk)
329

    
330
  def testSingleInstanceOnFailingNode(self):
331
    (inst, _) = self._SetUpInstanceSingleDisk()
332
    op = opcodes.OpClusterRepairDiskSizes(instances=[inst.name])
333

    
334
    self.rpc.call_blockdev_getdimensions.return_value = \
335
      self.RpcResultsBuilder() \
336
        .CreateFailedNodeResult(self.master)
337

    
338
    self.ExecOpCode(op)
339

    
340
    self.mcpu.assertLogContainsRegex("Failure in blockdev_getdimensions")
341

    
342
  def _ExecOpClusterRepairDiskSizes(self, node_data):
343
    # not specifying instances repairs all
344
    op = opcodes.OpClusterRepairDiskSizes()
345

    
346
    self.rpc.call_blockdev_getdimensions.return_value = \
347
      self.RpcResultsBuilder() \
348
        .CreateSuccessfulNodeResult(self.master, node_data)
349

    
350
    return self.ExecOpCode(op)
351

    
352
  def testInvalidResultData(self):
353
    for data in [[], [None], ["invalid"], [("still", "invalid")]]:
354
      self.ResetMocks()
355

    
356
      self._SetUpInstanceSingleDisk()
357
      self._ExecOpClusterRepairDiskSizes(data)
358

    
359
      self.mcpu.assertLogContainsRegex("ignoring")
360

    
361
  def testCorrectSize(self):
362
    self._SetUpInstanceSingleDisk()
363
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
364
    self.mcpu.assertLogIsEmpty()
365
    self.assertEqual(0, len(changed))
366

    
367
  def testWrongSize(self):
368
    self._SetUpInstanceSingleDisk()
369
    changed = self._ExecOpClusterRepairDiskSizes([(512 * 1024 * 1024, None)])
370
    self.assertEqual(1, len(changed))
371

    
372
  def testCorrectDRBD(self):
373
    self._SetUpInstanceSingleDisk(dev_type=constants.DT_DRBD8)
374
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
375
    self.mcpu.assertLogIsEmpty()
376
    self.assertEqual(0, len(changed))
377

    
378
  def testWrongDRBDChild(self):
379
    (_, disk) = self._SetUpInstanceSingleDisk(dev_type=constants.DT_DRBD8)
380
    disk.children[0].size = 512
381
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
382
    self.assertEqual(1, len(changed))
383

    
384
  def testExclusiveStorageInvalidResultData(self):
385
    self._SetUpInstanceSingleDisk()
386
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
387
    self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
388

    
389
    self.mcpu.assertLogContainsRegex(
390
      "did not return valid spindles information")
391

    
392
  def testExclusiveStorageCorrectSpindles(self):
393
    (_, disk) = self._SetUpInstanceSingleDisk()
394
    disk.spindles = 1
395
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
396
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
397
    self.assertEqual(0, len(changed))
398

    
399
  def testExclusiveStorageWrongSpindles(self):
400
    self._SetUpInstanceSingleDisk()
401
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
402
    changed = self._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
403
    self.assertEqual(1, len(changed))
404

    
405

    
406
class TestLUClusterSetParams(CmdlibTestCase):
407
  UID_POOL = [(10, 1000)]
408

    
409
  def testUidPool(self):
410
    op = opcodes.OpClusterSetParams(uid_pool=self.UID_POOL)
411
    self.ExecOpCode(op)
412
    self.assertEqual(self.UID_POOL, self.cluster.uid_pool)
413

    
414
  def testAddUids(self):
415
    old_pool = [(1, 9)]
416
    self.cluster.uid_pool = list(old_pool)
417
    op = opcodes.OpClusterSetParams(add_uids=self.UID_POOL)
418
    self.ExecOpCode(op)
419
    self.assertEqual(set(self.UID_POOL + old_pool),
420
                     set(self.cluster.uid_pool))
421

    
422
  def testRemoveUids(self):
423
    additional_pool = [(1, 9)]
424
    self.cluster.uid_pool = self.UID_POOL + additional_pool
425
    op = opcodes.OpClusterSetParams(remove_uids=self.UID_POOL)
426
    self.ExecOpCode(op)
427
    self.assertEqual(additional_pool, self.cluster.uid_pool)
428

    
429
  def testMasterNetmask(self):
430
    op = opcodes.OpClusterSetParams(master_netmask=26)
431
    self.ExecOpCode(op)
432
    self.assertEqual(26, self.cluster.master_netmask)
433

    
434
  def testInvalidDiskparams(self):
435
    for diskparams in [{constants.DT_DISKLESS: {constants.LV_STRIPES: 0}},
436
                       {constants.DT_DRBD8: {constants.RBD_POOL: "pool"}},
437
                       {constants.DT_DRBD8: {constants.RBD_ACCESS: "bunny"}}]:
438
      self.ResetMocks()
439
      op = opcodes.OpClusterSetParams(diskparams=diskparams)
440
      self.ExecOpCodeExpectOpPrereqError(op, "verify diskparams")
441

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

    
450
  def testMinimalDiskparams(self):
451
    diskparams = {constants.DT_RBD: {constants.RBD_POOL: "mock_pool"}}
452
    self.cluster.diskparams = {}
453
    op = opcodes.OpClusterSetParams(diskparams=diskparams)
454
    self.ExecOpCode(op)
455
    self.assertEqual(diskparams, self.cluster.diskparams)
456

    
457
  def testValidDiskparamsAccess(self):
458
    for value in constants.DISK_VALID_ACCESS_MODES:
459
      self.ResetMocks()
460
      op = opcodes.OpClusterSetParams(diskparams={
461
        constants.DT_RBD: {constants.RBD_ACCESS: value}
462
      })
463
      self.ExecOpCode(op)
464
      got = self.cluster.diskparams[constants.DT_RBD][constants.RBD_ACCESS]
465
      self.assertEqual(value, got)
466

    
467
  def testInvalidDiskparamsAccess(self):
468
    for value in ["default", "pinky_bunny"]:
469
      self.ResetMocks()
470
      op = opcodes.OpClusterSetParams(diskparams={
471
        constants.DT_RBD: {constants.RBD_ACCESS: value}
472
      })
473
      self.ExecOpCodeExpectOpPrereqError(op, "Invalid value of 'rbd:access'")
474

    
475
  def testUnsetDrbdHelperWithDrbdDisks(self):
476
    self.cfg.AddNewInstance(disks=[
477
      self.cfg.CreateDisk(dev_type=constants.DT_DRBD8, create_nodes=True)])
478
    op = opcodes.OpClusterSetParams(drbd_helper="")
479
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable drbd helper")
480

    
481
  def testFileStorageDir(self):
482
    op = opcodes.OpClusterSetParams(file_storage_dir="/random/path")
483
    self.ExecOpCode(op)
484

    
485
  def testSetFileStorageDirToCurrentValue(self):
486
    op = opcodes.OpClusterSetParams(
487
           file_storage_dir=self.cluster.file_storage_dir)
488
    self.ExecOpCode(op)
489

    
490
    self.mcpu.assertLogContainsRegex("file storage dir already set to value")
491

    
492
  def testUnsetFileStorageDirFileStorageEnabled(self):
493
    self.cfg.SetEnabledDiskTemplates([constants.DT_FILE])
494
    op = opcodes.OpClusterSetParams(file_storage_dir='')
495
    self.ExecOpCodeExpectOpPrereqError(op, "Unsetting the 'file' storage")
496

    
497
  def testUnsetFileStorageDirFileStorageDisabled(self):
498
    self.cfg.SetEnabledDiskTemplates([constants.DT_PLAIN])
499
    op = opcodes.OpClusterSetParams(file_storage_dir='')
500
    self.ExecOpCode(op)
501

    
502
  def testSetFileStorageDirFileStorageDisabled(self):
503
    self.cfg.SetEnabledDiskTemplates([constants.DT_PLAIN])
504
    op = opcodes.OpClusterSetParams(file_storage_dir='/some/path/')
505
    self.ExecOpCode(op)
506
    self.mcpu.assertLogContainsRegex("although file storage is not enabled")
507

    
508
  def testValidDrbdHelper(self):
509
    node1 = self.cfg.AddNewNode()
510
    node1.offline = True
511
    self.rpc.call_drbd_helper.return_value = \
512
      self.RpcResultsBuilder() \
513
        .AddSuccessfulNode(self.master, "/bin/true") \
514
        .AddOfflineNode(node1) \
515
        .Build()
516
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
517
    self.ExecOpCode(op)
518
    self.mcpu.assertLogContainsRegex("Not checking drbd helper on offline node")
519

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

    
528
  def testInvalidDrbdHelper(self):
529
    self.rpc.call_drbd_helper.return_value = \
530
      self.RpcResultsBuilder() \
531
        .AddSuccessfulNode(self.master, "/bin/false") \
532
        .Build()
533
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
534
    self.ExecOpCodeExpectOpPrereqError(op, "drbd helper is /bin/false")
535

    
536
  def testDrbdHelperWithoutDrbdDiskTemplate(self):
537
    drbd_helper = "/bin/random_helper"
538
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
539
    self.rpc.call_drbd_helper.return_value = \
540
      self.RpcResultsBuilder() \
541
        .AddSuccessfulNode(self.master, drbd_helper) \
542
        .Build()
543
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
544
    self.ExecOpCode(op)
545

    
546
    self.mcpu.assertLogContainsRegex("but did not enable")
547

    
548
  def testResetDrbdHelperDrbdDisabled(self):
549
    drbd_helper = ""
550
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
551
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
552
    self.ExecOpCode(op)
553

    
554
    self.assertEqual(None, self.cluster.drbd_usermode_helper)
555

    
556
  def testResetDrbdHelperDrbdEnabled(self):
557
    drbd_helper = ""
558
    self.cluster.enabled_disk_templates = [constants.DT_DRBD8]
559
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
560
    self.ExecOpCodeExpectOpPrereqError(
561
        op, "Cannot disable drbd helper while DRBD is enabled.")
562

    
563
  def testEnableDrbdNoHelper(self):
564
    self.cluster.enabled_disk_templates = [constants.DT_DISKLESS]
565
    self.cluster.drbd_usermode_helper = None
566
    enabled_disk_templates = [constants.DT_DRBD8]
567
    op = opcodes.OpClusterSetParams(
568
        enabled_disk_templates=enabled_disk_templates)
569
    self.ExecOpCodeExpectOpPrereqError(
570
        op, "Cannot enable DRBD without a DRBD usermode helper set")
571

    
572
  def testEnableDrbdHelperSet(self):
573
    drbd_helper = "/bin/random_helper"
574
    self.rpc.call_drbd_helper.return_value = \
575
      self.RpcResultsBuilder() \
576
        .AddSuccessfulNode(self.master, drbd_helper) \
577
        .Build()
578
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
579
    self.cluster.drbd_usermode_helper = drbd_helper
580
    enabled_disk_templates = [constants.DT_DRBD8]
581
    op = opcodes.OpClusterSetParams(
582
        enabled_disk_templates=enabled_disk_templates,
583
        ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
584
    self.ExecOpCode(op)
585

    
586
    self.assertEqual(drbd_helper, self.cluster.drbd_usermode_helper)
587

    
588
  def testDrbdHelperAlreadySet(self):
589
    drbd_helper = "/bin/true"
590
    self.rpc.call_drbd_helper.return_value = \
591
      self.RpcResultsBuilder() \
592
        .AddSuccessfulNode(self.master, "/bin/true") \
593
        .Build()
594
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
595
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
596
    self.ExecOpCode(op)
597

    
598
    self.assertEqual(drbd_helper, self.cluster.drbd_usermode_helper)
599
    self.mcpu.assertLogContainsRegex("DRBD helper already in desired state")
600

    
601
  def testSetDrbdHelper(self):
602
    drbd_helper = "/bin/true"
603
    self.rpc.call_drbd_helper.return_value = \
604
      self.RpcResultsBuilder() \
605
        .AddSuccessfulNode(self.master, "/bin/true") \
606
        .Build()
607
    self.cluster.drbd_usermode_helper = "/bin/false"
608
    self.cfg.SetEnabledDiskTemplates([constants.DT_DRBD8])
609
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
610
    self.ExecOpCode(op)
611

    
612
    self.assertEqual(drbd_helper, self.cluster.drbd_usermode_helper)
613

    
614
  def testBeparams(self):
615
    beparams = {constants.BE_VCPUS: 32}
616
    op = opcodes.OpClusterSetParams(beparams=beparams)
617
    self.ExecOpCode(op)
618
    self.assertEqual(32, self.cluster
619
                           .beparams[constants.PP_DEFAULT][constants.BE_VCPUS])
620

    
621
  def testNdparams(self):
622
    ndparams = {constants.ND_EXCLUSIVE_STORAGE: True}
623
    op = opcodes.OpClusterSetParams(ndparams=ndparams)
624
    self.ExecOpCode(op)
625
    self.assertEqual(True, self.cluster
626
                             .ndparams[constants.ND_EXCLUSIVE_STORAGE])
627

    
628
  def testNdparamsResetOobProgram(self):
629
    ndparams = {constants.ND_OOB_PROGRAM: ""}
630
    op = opcodes.OpClusterSetParams(ndparams=ndparams)
631
    self.ExecOpCode(op)
632
    self.assertEqual(constants.NDC_DEFAULTS[constants.ND_OOB_PROGRAM],
633
                     self.cluster.ndparams[constants.ND_OOB_PROGRAM])
634

    
635
  def testHvState(self):
636
    hv_state = {constants.HT_FAKE: {constants.HVST_CPU_TOTAL: 8}}
637
    op = opcodes.OpClusterSetParams(hv_state=hv_state)
638
    self.ExecOpCode(op)
639
    self.assertEqual(8, self.cluster.hv_state_static
640
                          [constants.HT_FAKE][constants.HVST_CPU_TOTAL])
641

    
642
  def testDiskState(self):
643
    disk_state = {
644
      constants.DT_PLAIN: {
645
        "mock_vg": {constants.DS_DISK_TOTAL: 10}
646
      }
647
    }
648
    op = opcodes.OpClusterSetParams(disk_state=disk_state)
649
    self.ExecOpCode(op)
650
    self.assertEqual(10, self.cluster
651
                           .disk_state_static[constants.DT_PLAIN]["mock_vg"]
652
                             [constants.DS_DISK_TOTAL])
653

    
654
  def testDefaultIPolicy(self):
655
    ipolicy = constants.IPOLICY_DEFAULTS
656
    op = opcodes.OpClusterSetParams(ipolicy=ipolicy)
657
    self.ExecOpCode(op)
658

    
659
  def testIPolicyNewViolation(self):
660
    import ganeti.constants as C
661
    ipolicy = C.IPOLICY_DEFAULTS
662
    ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MIN][C.ISPEC_MEM_SIZE] = 128
663
    ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MAX][C.ISPEC_MEM_SIZE] = 128
664

    
665
    self.cfg.AddNewInstance(beparams={C.BE_MINMEM: 512, C.BE_MAXMEM: 512})
666
    op = opcodes.OpClusterSetParams(ipolicy=ipolicy)
667
    self.ExecOpCode(op)
668

    
669
    self.mcpu.assertLogContainsRegex("instances violate them")
670

    
671
  def testNicparamsNoInstance(self):
672
    nicparams = {
673
      constants.NIC_LINK: "mock_bridge"
674
    }
675
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
676
    self.ExecOpCode(op)
677

    
678
    self.assertEqual("mock_bridge",
679
                     self.cluster.nicparams
680
                       [constants.PP_DEFAULT][constants.NIC_LINK])
681

    
682
  def testNicparamsInvalidConf(self):
683
    nicparams = {
684
      constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
685
      constants.NIC_LINK: ""
686
    }
687
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
688
    self.ExecOpCodeExpectException(op, errors.ConfigurationError, "NIC link")
689

    
690
  def testNicparamsInvalidInstanceConf(self):
691
    nicparams = {
692
      constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
693
      constants.NIC_LINK: "mock_bridge"
694
    }
695
    self.cfg.AddNewInstance(nics=[
696
      self.cfg.CreateNic(nicparams={constants.NIC_LINK: None})])
697
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
698
    self.ExecOpCodeExpectOpPrereqError(op, "Missing bridged NIC link")
699

    
700
  def testNicparamsMissingIp(self):
701
    nicparams = {
702
      constants.NIC_MODE: constants.NIC_MODE_ROUTED
703
    }
704
    self.cfg.AddNewInstance()
705
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
706
    self.ExecOpCodeExpectOpPrereqError(op, "routed NIC with no ip address")
707

    
708
  def testNicparamsWithInstance(self):
709
    nicparams = {
710
      constants.NIC_LINK: "mock_bridge"
711
    }
712
    self.cfg.AddNewInstance()
713
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
714
    self.ExecOpCode(op)
715

    
716
  def testDefaultHvparams(self):
717
    hvparams = constants.HVC_DEFAULTS
718
    op = opcodes.OpClusterSetParams(hvparams=hvparams)
719
    self.ExecOpCode(op)
720

    
721
    self.assertEqual(hvparams, self.cluster.hvparams)
722

    
723
  def testMinimalHvparams(self):
724
    hvparams = {
725
      constants.HT_FAKE: {
726
        constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE
727
      }
728
    }
729
    self.cluster.hvparams = {}
730
    op = opcodes.OpClusterSetParams(hvparams=hvparams)
731
    self.ExecOpCode(op)
732

    
733
    self.assertEqual(hvparams, self.cluster.hvparams)
734

    
735
  def testOsHvp(self):
736
    os_hvp = {
737
      "mocked_os": {
738
        constants.HT_FAKE: {
739
          constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE
740
        }
741
      },
742
      "other_os": constants.HVC_DEFAULTS
743
    }
744
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
745
    self.ExecOpCode(op)
746

    
747
    self.assertEqual(constants.HT_MIGRATION_NONLIVE,
748
                     self.cluster.os_hvp["mocked_os"][constants.HT_FAKE]
749
                       [constants.HV_MIGRATION_MODE])
750
    self.assertEqual(constants.HVC_DEFAULTS, self.cluster.os_hvp["other_os"])
751

    
752
  def testRemoveOsHvp(self):
753
    os_hvp = {"mocked_os": {constants.HT_FAKE: None}}
754
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
755
    self.ExecOpCode(op)
756

    
757
    assert constants.HT_FAKE not in self.cluster.os_hvp["mocked_os"]
758

    
759
  def testDefaultOsHvp(self):
760
    os_hvp = {"mocked_os": constants.HVC_DEFAULTS.copy()}
761
    self.cluster.os_hvp = {"mocked_os": {}}
762
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
763
    self.ExecOpCode(op)
764

    
765
    self.assertEqual(os_hvp, self.cluster.os_hvp)
766

    
767
  def testOsparams(self):
768
    osparams = {
769
      "mocked_os": {
770
        "param1": "value1",
771
        "param2": None
772
      },
773
      "other_os": {
774
        "param1": None
775
      }
776
    }
777
    self.cluster.osparams = {"other_os": {"param1": "value1"}}
778
    op = opcodes.OpClusterSetParams(osparams=osparams)
779
    self.ExecOpCode(op)
780

    
781
    self.assertEqual({"mocked_os": {"param1": "value1"}}, self.cluster.osparams)
782

    
783
  def testEnabledHypervisors(self):
784
    enabled_hypervisors = [constants.HT_XEN_HVM, constants.HT_XEN_PVM]
785
    op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors)
786
    self.ExecOpCode(op)
787

    
788
    self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors)
789

    
790
  def testEnabledHypervisorsWithoutHypervisorParams(self):
791
    enabled_hypervisors = [constants.HT_FAKE]
792
    self.cluster.hvparams = {}
793
    op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors)
794
    self.ExecOpCode(op)
795

    
796
    self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors)
797
    self.assertEqual(constants.HVC_DEFAULTS[constants.HT_FAKE],
798
                     self.cluster.hvparams[constants.HT_FAKE])
799

    
800
  @testutils.patch_object(utils, "FindFile")
801
  def testValidDefaultIallocator(self, find_file_mock):
802
    find_file_mock.return_value = "/random/path"
803
    default_iallocator = "/random/path"
804
    op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator)
805
    self.ExecOpCode(op)
806

    
807
    self.assertEqual(default_iallocator, self.cluster.default_iallocator)
808

    
809
  @testutils.patch_object(utils, "FindFile")
810
  def testInvalidDefaultIallocator(self, find_file_mock):
811
    find_file_mock.return_value = None
812
    default_iallocator = "/random/path"
813
    op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator)
814
    self.ExecOpCodeExpectOpPrereqError(op, "Invalid default iallocator script")
815

    
816
  def testEnabledDiskTemplates(self):
817
    enabled_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN]
818
    op = opcodes.OpClusterSetParams(
819
           enabled_disk_templates=enabled_disk_templates,
820
           ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
821
    self.ExecOpCode(op)
822

    
823
    self.assertEqual(enabled_disk_templates,
824
                     self.cluster.enabled_disk_templates)
825

    
826
  def testEnabledDiskTemplatesVsIpolicy(self):
827
    enabled_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN]
828
    op = opcodes.OpClusterSetParams(
829
           enabled_disk_templates=enabled_disk_templates,
830
           ipolicy={constants.IPOLICY_DTS: [constants.DT_FILE]})
831
    self.ExecOpCodeExpectOpPrereqError(op, "but not enabled on the cluster")
832

    
833
  def testDisablingDiskTemplatesOfInstances(self):
834
    old_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN]
835
    self.cfg.SetEnabledDiskTemplates(old_disk_templates)
836
    self.cfg.AddNewInstance(
837
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_PLAIN)])
838
    new_disk_templates = [constants.DT_DISKLESS, constants.DT_DRBD8]
839
    op = opcodes.OpClusterSetParams(
840
           enabled_disk_templates=new_disk_templates,
841
           ipolicy={constants.IPOLICY_DTS: new_disk_templates})
842
    self.ExecOpCodeExpectOpPrereqError(op, "least one instance using it")
843

    
844
  def testEnabledDiskTemplatesWithoutVgName(self):
845
    enabled_disk_templates = [constants.DT_PLAIN]
846
    self.cluster.volume_group_name = None
847
    op = opcodes.OpClusterSetParams(
848
           enabled_disk_templates=enabled_disk_templates)
849
    self.ExecOpCodeExpectOpPrereqError(op, "specify a volume group")
850

    
851
  def testDisableDiskTemplateWithExistingInstance(self):
852
    enabled_disk_templates = [constants.DT_DISKLESS]
853
    self.cfg.AddNewInstance(
854
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_PLAIN)])
855
    op = opcodes.OpClusterSetParams(
856
           enabled_disk_templates=enabled_disk_templates,
857
           ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
858
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable disk template")
859

    
860
  def testVgNameNoLvmDiskTemplateEnabled(self):
861
    vg_name = "test_vg"
862
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
863
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
864
    self.ExecOpCode(op)
865

    
866
    self.assertEqual(vg_name, self.cluster.volume_group_name)
867
    self.mcpu.assertLogIsEmpty()
868

    
869
  def testUnsetVgNameWithLvmDiskTemplateEnabled(self):
870
    vg_name = ""
871
    self.cluster.enabled_disk_templates = [constants.DT_PLAIN]
872
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
873
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group")
874

    
875
  def testUnsetVgNameWithLvmInstance(self):
876
    vg_name = ""
877
    self.cfg.AddNewInstance(
878
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_PLAIN)])
879
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
880
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group")
881

    
882
  def testUnsetVgNameWithNoLvmDiskTemplateEnabled(self):
883
    vg_name = ""
884
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
885
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
886
    self.ExecOpCode(op)
887

    
888
    self.assertEqual(None, self.cluster.volume_group_name)
889

    
890
  def testVgNameToOldName(self):
891
    vg_name = self.cluster.volume_group_name
892
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
893
    self.ExecOpCode(op)
894

    
895
    self.mcpu.assertLogContainsRegex("already in desired state")
896

    
897
  def testVgNameWithFailingNode(self):
898
    vg_name = "test_vg"
899
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
900
    self.rpc.call_vg_list.return_value = \
901
      self.RpcResultsBuilder() \
902
        .AddFailedNode(self.master) \
903
        .Build()
904
    self.ExecOpCode(op)
905

    
906
    self.mcpu.assertLogContainsRegex("Error while gathering data on node")
907

    
908
  def testVgNameWithValidNode(self):
909
    vg_name = "test_vg"
910
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
911
    self.rpc.call_vg_list.return_value = \
912
      self.RpcResultsBuilder() \
913
        .AddSuccessfulNode(self.master, {vg_name: 1024 * 1024}) \
914
        .Build()
915
    self.ExecOpCode(op)
916

    
917
  def testVgNameWithTooSmallNode(self):
918
    vg_name = "test_vg"
919
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
920
    self.rpc.call_vg_list.return_value = \
921
      self.RpcResultsBuilder() \
922
        .AddSuccessfulNode(self.master, {vg_name: 1}) \
923
        .Build()
924
    self.ExecOpCodeExpectOpPrereqError(op, "too small")
925

    
926
  def testMiscParameters(self):
927
    op = opcodes.OpClusterSetParams(candidate_pool_size=123,
928
                                    maintain_node_health=True,
929
                                    modify_etc_hosts=True,
930
                                    prealloc_wipe_disks=True,
931
                                    reserved_lvs=["/dev/mock_lv"],
932
                                    use_external_mip_script=True)
933
    self.ExecOpCode(op)
934

    
935
    self.mcpu.assertLogIsEmpty()
936
    self.assertEqual(123, self.cluster.candidate_pool_size)
937
    self.assertEqual(True, self.cluster.maintain_node_health)
938
    self.assertEqual(True, self.cluster.modify_etc_hosts)
939
    self.assertEqual(True, self.cluster.prealloc_wipe_disks)
940
    self.assertEqual(["/dev/mock_lv"], self.cluster.reserved_lvs)
941
    self.assertEqual(True, self.cluster.use_external_mip_script)
942

    
943
  def testAddHiddenOs(self):
944
    self.cluster.hidden_os = ["hidden1", "hidden2"]
945
    op = opcodes.OpClusterSetParams(hidden_os=[(constants.DDM_ADD, "hidden2"),
946
                                               (constants.DDM_ADD, "hidden3")])
947
    self.ExecOpCode(op)
948

    
949
    self.assertEqual(["hidden1", "hidden2", "hidden3"], self.cluster.hidden_os)
950
    self.mcpu.assertLogContainsRegex("OS hidden2 already")
951

    
952
  def testRemoveBlacklistedOs(self):
953
    self.cluster.blacklisted_os = ["blisted1", "blisted2"]
954
    op = opcodes.OpClusterSetParams(blacklisted_os=[
955
                                      (constants.DDM_REMOVE, "blisted2"),
956
                                      (constants.DDM_REMOVE, "blisted3")])
957
    self.ExecOpCode(op)
958

    
959
    self.assertEqual(["blisted1"], self.cluster.blacklisted_os)
960
    self.mcpu.assertLogContainsRegex("OS blisted3 not found")
961

    
962
  def testMasterNetdev(self):
963
    master_netdev = "test_dev"
964
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev)
965
    self.ExecOpCode(op)
966

    
967
    self.assertEqual(master_netdev, self.cluster.master_netdev)
968

    
969
  def testMasterNetdevFailNoForce(self):
970
    master_netdev = "test_dev"
971
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev)
972
    self.rpc.call_node_deactivate_master_ip.return_value = \
973
      self.RpcResultsBuilder() \
974
        .CreateFailedNodeResult(self.master)
975
    self.ExecOpCodeExpectOpExecError(op, "Could not disable the master ip")
976

    
977
  def testMasterNetdevFailForce(self):
978
    master_netdev = "test_dev"
979
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev,
980
                                    force=True)
981
    self.rpc.call_node_deactivate_master_ip.return_value = \
982
      self.RpcResultsBuilder() \
983
        .CreateFailedNodeResult(self.master)
984
    self.ExecOpCode(op)
985

    
986
    self.mcpu.assertLogContainsRegex("Could not disable the master ip")
987

    
988

    
989
class TestLUClusterVerify(CmdlibTestCase):
990
  def testVerifyAllGroups(self):
991
    op = opcodes.OpClusterVerify()
992
    result = self.ExecOpCode(op)
993

    
994
    self.assertEqual(2, len(result["jobs"]))
995

    
996
  def testVerifyDefaultGroups(self):
997
    op = opcodes.OpClusterVerify(group_name="default")
998
    result = self.ExecOpCode(op)
999

    
1000
    self.assertEqual(1, len(result["jobs"]))
1001

    
1002

    
1003
class TestLUClusterVerifyConfig(CmdlibTestCase):
1004

    
1005
  def setUp(self):
1006
    super(TestLUClusterVerifyConfig, self).setUp()
1007

    
1008
    self._load_cert_patcher = testutils \
1009
      .patch_object(OpenSSL.crypto, "load_certificate")
1010
    self._load_cert_mock = self._load_cert_patcher.start()
1011
    self._verify_cert_patcher = testutils \
1012
      .patch_object(utils, "VerifyX509Certificate")
1013
    self._verify_cert_mock = self._verify_cert_patcher.start()
1014
    self._read_file_patcher = testutils.patch_object(utils, "ReadFile")
1015
    self._read_file_mock = self._read_file_patcher.start()
1016
    self._can_read_patcher = testutils.patch_object(utils, "CanRead")
1017
    self._can_read_mock = self._can_read_patcher.start()
1018

    
1019
    self._can_read_mock.return_value = True
1020
    self._read_file_mock.return_value = True
1021
    self._verify_cert_mock.return_value = (None, "")
1022
    self._load_cert_mock.return_value = True
1023

    
1024
  def tearDown(self):
1025
    super(TestLUClusterVerifyConfig, self).tearDown()
1026

    
1027
    self._can_read_patcher.stop()
1028
    self._read_file_patcher.stop()
1029
    self._verify_cert_patcher.stop()
1030
    self._load_cert_patcher.stop()
1031

    
1032
  def testSuccessfulRun(self):
1033
    self.cfg.AddNewInstance()
1034
    op = opcodes.OpClusterVerifyConfig()
1035
    result = self.ExecOpCode(op)
1036

    
1037
    self.assertTrue(result)
1038

    
1039
  def testDanglingNode(self):
1040
    node = self.cfg.AddNewNode()
1041
    self.cfg.AddNewInstance(primary_node=node)
1042
    node.group = "invalid"
1043
    op = opcodes.OpClusterVerifyConfig()
1044
    result = self.ExecOpCode(op)
1045

    
1046
    self.mcpu.assertLogContainsRegex(
1047
      "following nodes \(and their instances\) belong to a non existing group")
1048
    self.assertFalse(result)
1049

    
1050
  def testDanglingInstance(self):
1051
    inst = self.cfg.AddNewInstance()
1052
    inst.primary_node = "invalid"
1053
    op = opcodes.OpClusterVerifyConfig()
1054
    result = self.ExecOpCode(op)
1055

    
1056
    self.mcpu.assertLogContainsRegex(
1057
      "following instances have a non-existing primary-node")
1058
    self.assertFalse(result)
1059

    
1060

    
1061
class TestLUClusterVerifyGroup(CmdlibTestCase):
1062
  def testEmptyNodeGroup(self):
1063
    group = self.cfg.AddNewNodeGroup()
1064
    op = opcodes.OpClusterVerifyGroup(group_name=group.name, verbose=True)
1065

    
1066
    result = self.ExecOpCode(op)
1067

    
1068
    self.assertTrue(result)
1069
    self.mcpu.assertLogContainsRegex("Empty node group, skipping verification")
1070

    
1071
  def testSimpleInvocation(self):
1072
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1073

    
1074
    self.ExecOpCode(op)
1075

    
1076
  def testSimpleInvocationWithInstance(self):
1077
    self.cfg.AddNewInstance(disks=[])
1078
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1079

    
1080
    self.ExecOpCode(op)
1081

    
1082
  def testGhostNode(self):
1083
    group = self.cfg.AddNewNodeGroup()
1084
    node = self.cfg.AddNewNode(group=group.uuid, offline=True)
1085
    self.master.offline = True
1086
    self.cfg.AddNewInstance(disk_template=constants.DT_DRBD8,
1087
                            primary_node=self.master,
1088
                            secondary_node=node)
1089

    
1090
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
1091
      RpcResultsBuilder() \
1092
        .AddOfflineNode(self.master) \
1093
        .Build()
1094

    
1095
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1096

    
1097
    self.ExecOpCode(op)
1098

    
1099
  def testValidRpcResult(self):
1100
    self.cfg.AddNewInstance(disks=[])
1101

    
1102
    self.rpc.call_node_verify.return_value = \
1103
      RpcResultsBuilder() \
1104
        .AddSuccessfulNode(self.master, {}) \
1105
        .Build()
1106

    
1107
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
1108

    
1109
    self.ExecOpCode(op)
1110

    
1111

    
1112
class TestLUClusterVerifyGroupMethods(CmdlibTestCase):
1113
  """Base class for testing individual methods in LUClusterVerifyGroup.
1114

1115
  """
1116
  def setUp(self):
1117
    super(TestLUClusterVerifyGroupMethods, self).setUp()
1118
    self.op = opcodes.OpClusterVerifyGroup(group_name="default")
1119

    
1120
  def PrepareLU(self, lu):
1121
    lu._exclusive_storage = False
1122
    lu.master_node = self.master_uuid
1123
    lu.group_info = self.group
1124
    cluster.LUClusterVerifyGroup.all_node_info = \
1125
      property(fget=lambda _: self.cfg.GetAllNodesInfo())
1126

    
1127

    
1128
class TestLUClusterVerifyGroupVerifyNode(TestLUClusterVerifyGroupMethods):
1129
  @withLockedLU
1130
  def testInvalidNodeResult(self, lu):
1131
    self.assertFalse(lu._VerifyNode(self.master, None))
1132
    self.assertFalse(lu._VerifyNode(self.master, ""))
1133

    
1134
  @withLockedLU
1135
  def testInvalidVersion(self, lu):
1136
    self.assertFalse(lu._VerifyNode(self.master, {"version": None}))
1137
    self.assertFalse(lu._VerifyNode(self.master, {"version": ""}))
1138
    self.assertFalse(lu._VerifyNode(self.master, {
1139
      "version": (constants.PROTOCOL_VERSION - 1, constants.RELEASE_VERSION)
1140
    }))
1141

    
1142
    self.mcpu.ClearLogMessages()
1143
    self.assertTrue(lu._VerifyNode(self.master, {
1144
      "version": (constants.PROTOCOL_VERSION, constants.RELEASE_VERSION + "x")
1145
    }))
1146
    self.mcpu.assertLogContainsRegex("software version mismatch")
1147

    
1148
  def _GetValidNodeResult(self, additional_fields):
1149
    ret = {
1150
      "version": (constants.PROTOCOL_VERSION, constants.RELEASE_VERSION),
1151
      constants.NV_NODESETUP: []
1152
    }
1153
    ret.update(additional_fields)
1154
    return ret
1155

    
1156
  @withLockedLU
1157
  def testHypervisor(self, lu):
1158
    lu._VerifyNode(self.master, self._GetValidNodeResult({
1159
      constants.NV_HYPERVISOR: {
1160
        constants.HT_XEN_PVM: None,
1161
        constants.HT_XEN_HVM: "mock error"
1162
      }
1163
    }))
1164
    self.mcpu.assertLogContainsRegex(constants.HT_XEN_HVM)
1165
    self.mcpu.assertLogContainsRegex("mock error")
1166

    
1167
  @withLockedLU
1168
  def testHvParams(self, lu):
1169
    lu._VerifyNode(self.master, self._GetValidNodeResult({
1170
      constants.NV_HVPARAMS: [("mock item", constants.HT_XEN_HVM, "mock error")]
1171
    }))
1172
    self.mcpu.assertLogContainsRegex(constants.HT_XEN_HVM)
1173
    self.mcpu.assertLogContainsRegex("mock item")
1174
    self.mcpu.assertLogContainsRegex("mock error")
1175

    
1176
  @withLockedLU
1177
  def testSuccessfulResult(self, lu):
1178
    self.assertTrue(lu._VerifyNode(self.master, self._GetValidNodeResult({})))
1179
    self.mcpu.assertLogIsEmpty()
1180

    
1181

    
1182
class TestLUClusterVerifyGroupVerifyNodeTime(TestLUClusterVerifyGroupMethods):
1183
  @withLockedLU
1184
  def testInvalidNodeResult(self, lu):
1185
    for ndata in [{}, {constants.NV_TIME: "invalid"}]:
1186
      self.mcpu.ClearLogMessages()
1187
      lu._VerifyNodeTime(self.master, ndata, None, None)
1188

    
1189
      self.mcpu.assertLogContainsRegex("Node returned invalid time")
1190

    
1191
  @withLockedLU
1192
  def testNodeDiverges(self, lu):
1193
    for ntime in [(0, 0), (2000, 0)]:
1194
      self.mcpu.ClearLogMessages()
1195
      lu._VerifyNodeTime(self.master, {constants.NV_TIME: ntime}, 1000, 1005)
1196

    
1197
      self.mcpu.assertLogContainsRegex("Node time diverges")
1198

    
1199
  @withLockedLU
1200
  def testSuccessfulResult(self, lu):
1201
    lu._VerifyNodeTime(self.master, {constants.NV_TIME: (0, 0)}, 0, 5)
1202
    self.mcpu.assertLogIsEmpty()
1203

    
1204

    
1205
class TestLUClusterVerifyGroupUpdateVerifyNodeLVM(
1206
        TestLUClusterVerifyGroupMethods):
1207
  def setUp(self):
1208
    super(TestLUClusterVerifyGroupUpdateVerifyNodeLVM, self).setUp()
1209
    self.VALID_NRESULT = {
1210
      constants.NV_VGLIST: {"mock_vg": 30000},
1211
      constants.NV_PVLIST: [
1212
        {
1213
          "name": "mock_pv",
1214
          "vg_name": "mock_vg",
1215
          "size": 5000,
1216
          "free": 2500,
1217
          "attributes": [],
1218
          "lv_list": []
1219
        }
1220
      ]
1221
    }
1222

    
1223
  @withLockedLU
1224
  def testNoVgName(self, lu):
1225
    lu._UpdateVerifyNodeLVM(self.master, {}, None, None)
1226
    self.mcpu.assertLogIsEmpty()
1227

    
1228
  @withLockedLU
1229
  def testEmptyNodeResult(self, lu):
1230
    lu._UpdateVerifyNodeLVM(self.master, {}, "mock_vg", None)
1231
    self.mcpu.assertLogContainsRegex("unable to check volume groups")
1232
    self.mcpu.assertLogContainsRegex("Can't get PV list from node")
1233

    
1234
  @withLockedLU
1235
  def testValidNodeResult(self, lu):
1236
    lu._UpdateVerifyNodeLVM(self.master, self.VALID_NRESULT, "mock_vg", None)
1237
    self.mcpu.assertLogIsEmpty()
1238

    
1239
  @withLockedLU
1240
  def testValidNodeResultExclusiveStorage(self, lu):
1241
    lu._exclusive_storage = True
1242
    lu._UpdateVerifyNodeLVM(self.master, self.VALID_NRESULT, "mock_vg",
1243
                            cluster.LUClusterVerifyGroup.NodeImage())
1244
    self.mcpu.assertLogIsEmpty()
1245

    
1246

    
1247
class TestLUClusterVerifyGroupVerifyGroupDRBDVersion(
1248
        TestLUClusterVerifyGroupMethods):
1249
  @withLockedLU
1250
  def testEmptyNodeResult(self, lu):
1251
    lu._VerifyGroupDRBDVersion({})
1252
    self.mcpu.assertLogIsEmpty()
1253

    
1254
  @withLockedLU
1255
  def testValidNodeResult(self, lu):
1256
    lu._VerifyGroupDRBDVersion(
1257
      RpcResultsBuilder()
1258
        .AddSuccessfulNode(self.master, {
1259
          constants.NV_DRBDVERSION: "8.3.0"
1260
        })
1261
        .Build())
1262
    self.mcpu.assertLogIsEmpty()
1263

    
1264
  @withLockedLU
1265
  def testDifferentVersions(self, lu):
1266
    node1 = self.cfg.AddNewNode()
1267
    lu._VerifyGroupDRBDVersion(
1268
      RpcResultsBuilder()
1269
        .AddSuccessfulNode(self.master, {
1270
          constants.NV_DRBDVERSION: "8.3.0"
1271
        })
1272
        .AddSuccessfulNode(node1, {
1273
          constants.NV_DRBDVERSION: "8.4.0"
1274
        })
1275
        .Build())
1276
    self.mcpu.assertLogContainsRegex("DRBD version mismatch: 8.3.0")
1277
    self.mcpu.assertLogContainsRegex("DRBD version mismatch: 8.4.0")
1278

    
1279

    
1280
class TestLUClusterVerifyGroupVerifyGroupLVM(TestLUClusterVerifyGroupMethods):
1281
  @withLockedLU
1282
  def testNoVgName(self, lu):
1283
    lu._VerifyGroupLVM(None, None)
1284
    self.mcpu.assertLogIsEmpty()
1285

    
1286
  @withLockedLU
1287
  def testNoExclusiveStorage(self, lu):
1288
    lu._VerifyGroupLVM(None, "mock_vg")
1289
    self.mcpu.assertLogIsEmpty()
1290

    
1291
  @withLockedLU
1292
  def testNoPvInfo(self, lu):
1293
    lu._exclusive_storage = True
1294
    nimg = cluster.LUClusterVerifyGroup.NodeImage()
1295
    lu._VerifyGroupLVM({self.master.uuid: nimg}, "mock_vg")
1296
    self.mcpu.assertLogIsEmpty()
1297

    
1298
  @withLockedLU
1299
  def testValidPvInfos(self, lu):
1300
    lu._exclusive_storage = True
1301
    node2 = self.cfg.AddNewNode()
1302
    nimg1 = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master.uuid)
1303
    nimg1.pv_min = 10000
1304
    nimg1.pv_max = 10010
1305
    nimg2 = cluster.LUClusterVerifyGroup.NodeImage(uuid=node2.uuid)
1306
    nimg2.pv_min = 9998
1307
    nimg2.pv_max = 10005
1308
    lu._VerifyGroupLVM({self.master.uuid: nimg1, node2.uuid: nimg2}, "mock_vg")
1309
    self.mcpu.assertLogIsEmpty()
1310

    
1311

    
1312
class TestLUClusterVerifyGroupVerifyNodeBridges(
1313
        TestLUClusterVerifyGroupMethods):
1314
  @withLockedLU
1315
  def testNoBridges(self, lu):
1316
    lu._VerifyNodeBridges(None, None, None)
1317
    self.mcpu.assertLogIsEmpty()
1318

    
1319
  @withLockedLU
1320
  def testInvalidBridges(self, lu):
1321
    for ndata in [{}, {constants.NV_BRIDGES: ""}]:
1322
      self.mcpu.ClearLogMessages()
1323
      lu._VerifyNodeBridges(self.master, ndata, ["mock_bridge"])
1324
      self.mcpu.assertLogContainsRegex("not return valid bridge information")
1325

    
1326
    self.mcpu.ClearLogMessages()
1327
    lu._VerifyNodeBridges(self.master, {constants.NV_BRIDGES: ["mock_bridge"]},
1328
                          ["mock_bridge"])
1329
    self.mcpu.assertLogContainsRegex("missing bridge")
1330

    
1331

    
1332
class TestLUClusterVerifyGroupVerifyNodeUserScripts(
1333
        TestLUClusterVerifyGroupMethods):
1334
  @withLockedLU
1335
  def testNoUserScripts(self, lu):
1336
    lu._VerifyNodeUserScripts(self.master, {})
1337
    self.mcpu.assertLogContainsRegex("did not return user scripts information")
1338

    
1339
  @withLockedLU
1340
  def testBrokenUserScripts(self, lu):
1341
    lu._VerifyNodeUserScripts(self.master,
1342
                              {constants.NV_USERSCRIPTS: ["script"]})
1343
    self.mcpu.assertLogContainsRegex("scripts not present or not executable")
1344

    
1345

    
1346
class TestLUClusterVerifyGroupVerifyNodeNetwork(
1347
        TestLUClusterVerifyGroupMethods):
1348

    
1349
  def setUp(self):
1350
    super(TestLUClusterVerifyGroupVerifyNodeNetwork, self).setUp()
1351
    self.VALID_NRESULT = {
1352
      constants.NV_NODELIST: {},
1353
      constants.NV_NODENETTEST: {},
1354
      constants.NV_MASTERIP: True
1355
    }
1356

    
1357
  @withLockedLU
1358
  def testEmptyNodeResult(self, lu):
1359
    lu._VerifyNodeNetwork(self.master, {})
1360
    self.mcpu.assertLogContainsRegex(
1361
      "node hasn't returned node ssh connectivity data")
1362
    self.mcpu.assertLogContainsRegex(
1363
      "node hasn't returned node tcp connectivity data")
1364
    self.mcpu.assertLogContainsRegex(
1365
      "node hasn't returned node master IP reachability data")
1366

    
1367
  @withLockedLU
1368
  def testValidResult(self, lu):
1369
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1370
    self.mcpu.assertLogIsEmpty()
1371

    
1372
  @withLockedLU
1373
  def testSshProblem(self, lu):
1374
    self.VALID_NRESULT.update({
1375
      constants.NV_NODELIST: {
1376
        "mock_node": "mock_error"
1377
      }
1378
    })
1379
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1380
    self.mcpu.assertLogContainsRegex("ssh communication with node 'mock_node'")
1381

    
1382
  @withLockedLU
1383
  def testTcpProblem(self, lu):
1384
    self.VALID_NRESULT.update({
1385
      constants.NV_NODENETTEST: {
1386
        "mock_node": "mock_error"
1387
      }
1388
    })
1389
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1390
    self.mcpu.assertLogContainsRegex("tcp communication with node 'mock_node'")
1391

    
1392
  @withLockedLU
1393
  def testMasterIpNotReachable(self, lu):
1394
    self.VALID_NRESULT.update({
1395
      constants.NV_MASTERIP: False
1396
    })
1397
    node1 = self.cfg.AddNewNode()
1398
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1399
    self.mcpu.assertLogContainsRegex(
1400
      "the master node cannot reach the master IP")
1401

    
1402
    self.mcpu.ClearLogMessages()
1403
    lu._VerifyNodeNetwork(node1, self.VALID_NRESULT)
1404
    self.mcpu.assertLogContainsRegex("cannot reach the master IP")
1405

    
1406

    
1407
class TestLUClusterVerifyGroupVerifyInstance(TestLUClusterVerifyGroupMethods):
1408
  def setUp(self):
1409
    super(TestLUClusterVerifyGroupVerifyInstance, self).setUp()
1410

    
1411
    self.node1 = self.cfg.AddNewNode()
1412
    self.drbd_inst = self.cfg.AddNewInstance(
1413
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_DRBD8,
1414
                                 primary_node=self.master,
1415
                                 secondary_node=self.node1)])
1416
    self.running_inst = self.cfg.AddNewInstance(
1417
      admin_state=constants.ADMINST_UP, disks_active=True)
1418
    self.diskless_inst = self.cfg.AddNewInstance(disks=[])
1419

    
1420
    self.master_img = \
1421
      cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1422
    self.master_img.volumes = ["/".join(disk.logical_id)
1423
                               for inst in [self.running_inst,
1424
                                            self.diskless_inst]
1425
                               for disk in inst.disks]
1426
    self.master_img.volumes.extend(
1427
      ["/".join(disk.logical_id) for disk in self.drbd_inst.disks[0].children])
1428
    self.master_img.instances = [self.running_inst.uuid]
1429
    self.node1_img = \
1430
      cluster.LUClusterVerifyGroup.NodeImage(uuid=self.node1.uuid)
1431
    self.node1_img.volumes = \
1432
      ["/".join(disk.logical_id) for disk in self.drbd_inst.disks[0].children]
1433
    self.node_imgs = {
1434
      self.master_uuid: self.master_img,
1435
      self.node1.uuid: self.node1_img
1436
    }
1437
    self.diskstatus = {
1438
      self.master_uuid: [
1439
        (True, objects.BlockDevStatus(ldisk_status=constants.LDS_OKAY))
1440
        for _ in self.running_inst.disks
1441
      ]
1442
    }
1443

    
1444
  @withLockedLU
1445
  def testDisklessInst(self, lu):
1446
    lu._VerifyInstance(self.diskless_inst, self.node_imgs, {})
1447
    self.mcpu.assertLogIsEmpty()
1448

    
1449
  @withLockedLU
1450
  def testOfflineNode(self, lu):
1451
    self.master_img.offline = True
1452
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, {})
1453
    self.mcpu.assertLogIsEmpty()
1454

    
1455
  @withLockedLU
1456
  def testRunningOnOfflineNode(self, lu):
1457
    self.master_img.offline = True
1458
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1459
    self.mcpu.assertLogContainsRegex(
1460
      "instance is marked as running and lives on offline node")
1461

    
1462
  @withLockedLU
1463
  def testMissingVolume(self, lu):
1464
    self.master_img.volumes = []
1465
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1466
    self.mcpu.assertLogContainsRegex("volume .* missing")
1467

    
1468
  @withLockedLU
1469
  def testRunningInstanceOnWrongNode(self, lu):
1470
    self.master_img.instances = []
1471
    self.diskless_inst.admin_state = constants.ADMINST_UP
1472
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1473
    self.mcpu.assertLogContainsRegex("instance not running on its primary node")
1474

    
1475
  @withLockedLU
1476
  def testRunningInstanceOnRightNode(self, lu):
1477
    self.master_img.instances = [self.running_inst.uuid]
1478
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1479
    self.mcpu.assertLogIsEmpty()
1480

    
1481
  @withLockedLU
1482
  def testValidDiskStatus(self, lu):
1483
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1484
    self.mcpu.assertLogIsEmpty()
1485

    
1486
  @withLockedLU
1487
  def testDegradedDiskStatus(self, lu):
1488
    self.diskstatus[self.master_uuid][0][1].is_degraded = True
1489
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1490
    self.mcpu.assertLogContainsRegex("instance .* is degraded")
1491

    
1492
  @withLockedLU
1493
  def testNotOkayDiskStatus(self, lu):
1494
    self.diskstatus[self.master_uuid][0][1].ldisk_status = constants.LDS_FAULTY
1495
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1496
    self.mcpu.assertLogContainsRegex("instance .* state is 'faulty'")
1497

    
1498
  @withLockedLU
1499
  def testExclusiveStorageWithInvalidInstance(self, lu):
1500
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
1501
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1502
    self.mcpu.assertLogContainsRegex(
1503
      "instance has template drbd, which is not supported")
1504

    
1505
  @withLockedLU
1506
  def testExclusiveStorageWithValidInstance(self, lu):
1507
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
1508
    self.running_inst.disks[0].spindles = 1
1509
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1510
    self.mcpu.assertLogIsEmpty()
1511

    
1512
  @withLockedLU
1513
  def testDrbdInTwoGroups(self, lu):
1514
    group = self.cfg.AddNewNodeGroup()
1515
    self.node1.group = group.uuid
1516
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1517
    self.mcpu.assertLogContainsRegex(
1518
      "instance has primary and secondary nodes in different groups")
1519

    
1520
  @withLockedLU
1521
  def testOfflineSecondary(self, lu):
1522
    self.node1_img.offline = True
1523
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1524
    self.mcpu.assertLogContainsRegex("instance has offline secondary node\(s\)")
1525

    
1526

    
1527
class TestLUClusterVerifyGroupVerifyOrphanVolumes(
1528
        TestLUClusterVerifyGroupMethods):
1529
  @withLockedLU
1530
  def testOrphanedVolume(self, lu):
1531
    master_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1532
    master_img.volumes = ["mock_vg/disk_0", "mock_vg/disk_1", "mock_vg/disk_2"]
1533
    node_imgs = {
1534
      self.master_uuid: master_img
1535
    }
1536
    node_vol_should = {
1537
      self.master_uuid: ["mock_vg/disk_0"]
1538
    }
1539

    
1540
    lu._VerifyOrphanVolumes(node_vol_should, node_imgs,
1541
                            utils.FieldSet("mock_vg/disk_2"))
1542
    self.mcpu.assertLogContainsRegex("volume mock_vg/disk_1 is unknown")
1543
    self.mcpu.assertLogDoesNotContainRegex("volume mock_vg/disk_0 is unknown")
1544
    self.mcpu.assertLogDoesNotContainRegex("volume mock_vg/disk_2 is unknown")
1545

    
1546

    
1547
class TestLUClusterVerifyGroupVerifyNPlusOneMemory(
1548
        TestLUClusterVerifyGroupMethods):
1549
  @withLockedLU
1550
  def testN1Failure(self, lu):
1551
    group1 = self.cfg.AddNewNodeGroup()
1552

    
1553
    node1 = self.cfg.AddNewNode()
1554
    node2 = self.cfg.AddNewNode(group=group1)
1555
    node3 = self.cfg.AddNewNode()
1556

    
1557
    inst1 = self.cfg.AddNewInstance()
1558
    inst2 = self.cfg.AddNewInstance()
1559
    inst3 = self.cfg.AddNewInstance()
1560

    
1561
    node1_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node1.uuid)
1562
    node1_img.sbp = {
1563
      self.master_uuid: [inst1.uuid, inst2.uuid, inst3.uuid]
1564
    }
1565

    
1566
    node2_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node2.uuid)
1567

    
1568
    node3_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node3.uuid)
1569
    node3_img.offline = True
1570

    
1571
    node_imgs = {
1572
      node1.uuid: node1_img,
1573
      node2.uuid: node2_img,
1574
      node3.uuid: node3_img
1575
    }
1576

    
1577
    lu._VerifyNPlusOneMemory(node_imgs, self.cfg.GetAllInstancesInfo())
1578
    self.mcpu.assertLogContainsRegex(
1579
      "not enough memory to accomodate instance failovers")
1580

    
1581
    self.mcpu.ClearLogMessages()
1582
    node1_img.mfree = 1000
1583
    lu._VerifyNPlusOneMemory(node_imgs, self.cfg.GetAllInstancesInfo())
1584
    self.mcpu.assertLogIsEmpty()
1585

    
1586

    
1587
class TestLUClusterVerifyGroupVerifyFiles(TestLUClusterVerifyGroupMethods):
1588
  @withLockedLU
1589
  def test(self, lu):
1590
    node1 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1591
                                vm_capable=True)
1592
    node2 = self.cfg.AddNewNode(master_candidate=True, vm_capable=False)
1593
    node3 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1594
                                vm_capable=True)
1595
    node4 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1596
                                vm_capable=True)
1597
    node5 = self.cfg.AddNewNode(master_candidate=False, offline=True)
1598

    
1599
    nodeinfo = [self.master, node1, node2, node3, node4, node5]
1600
    files_all = set([
1601
      pathutils.CLUSTER_DOMAIN_SECRET_FILE,
1602
      pathutils.RAPI_CERT_FILE,
1603
      pathutils.RAPI_USERS_FILE,
1604
      ])
1605
    files_opt = set([
1606
      pathutils.RAPI_USERS_FILE,
1607
      hv_xen.XL_CONFIG_FILE,
1608
      pathutils.VNC_PASSWORD_FILE,
1609
      ])
1610
    files_mc = set([
1611
      pathutils.CLUSTER_CONF_FILE,
1612
      ])
1613
    files_vm = set([
1614
      hv_xen.XEND_CONFIG_FILE,
1615
      hv_xen.XL_CONFIG_FILE,
1616
      pathutils.VNC_PASSWORD_FILE,
1617
      ])
1618
    nvinfo = RpcResultsBuilder() \
1619
      .AddSuccessfulNode(self.master, {
1620
        constants.NV_FILELIST: {
1621
          pathutils.CLUSTER_CONF_FILE: "82314f897f38b35f9dab2f7c6b1593e0",
1622
          pathutils.RAPI_CERT_FILE: "babbce8f387bc082228e544a2146fee4",
1623
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1624
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
1625
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
1626
        }}) \
1627
      .AddSuccessfulNode(node1, {
1628
        constants.NV_FILELIST: {
1629
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1630
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
1631
          }
1632
        }) \
1633
      .AddSuccessfulNode(node2, {
1634
        constants.NV_FILELIST: {
1635
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1636
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1637
          }
1638
        }) \
1639
      .AddSuccessfulNode(node3, {
1640
        constants.NV_FILELIST: {
1641
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1642
          pathutils.CLUSTER_CONF_FILE: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
1643
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1644
          pathutils.RAPI_USERS_FILE: "rapiusers-ea3271e8d810ef3",
1645
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
1646
          }
1647
        }) \
1648
      .AddSuccessfulNode(node4, {}) \
1649
      .AddOfflineNode(node5) \
1650
      .Build()
1651
    assert set(nvinfo.keys()) == set(map(operator.attrgetter("uuid"), nodeinfo))
1652

    
1653
    lu._VerifyFiles(nodeinfo, self.master_uuid, nvinfo,
1654
                    (files_all, files_opt, files_mc, files_vm))
1655

    
1656
    expected_msgs = [
1657
      "File %s found with 2 different checksums (variant 1 on"
1658
        " %s, %s, %s; variant 2 on %s)" %
1659
        (pathutils.RAPI_CERT_FILE, node1.name, node2.name, node3.name,
1660
         self.master.name),
1661
      "File %s is missing from node(s) %s" %
1662
        (pathutils.CLUSTER_DOMAIN_SECRET_FILE, node1.name),
1663
      "File %s should not exist on node(s) %s" %
1664
        (pathutils.CLUSTER_CONF_FILE, node3.name),
1665
      "File %s is missing from node(s) %s" %
1666
        (hv_xen.XEND_CONFIG_FILE, node3.name),
1667
      "File %s is missing from node(s) %s" %
1668
        (pathutils.CLUSTER_CONF_FILE, node2.name),
1669
      "File %s found with 2 different checksums (variant 1 on"
1670
        " %s; variant 2 on %s)" %
1671
        (pathutils.CLUSTER_CONF_FILE, self.master.name, node3.name),
1672
      "File %s is optional, but it must exist on all or no nodes (not"
1673
        " found on %s, %s, %s)" %
1674
        (pathutils.RAPI_USERS_FILE, self.master.name, node1.name, node2.name),
1675
      "File %s is optional, but it must exist on all or no nodes (not"
1676
        " found on %s)" % (hv_xen.XL_CONFIG_FILE, node1.name),
1677
      "Node did not return file checksum data",
1678
      ]
1679

    
1680
    self.assertEqual(len(self.mcpu.GetLogMessages()), len(expected_msgs))
1681
    for expected_msg in expected_msgs:
1682
      self.mcpu.assertLogContainsInLine(expected_msg)
1683

    
1684

    
1685
class TestLUClusterVerifyGroupVerifyNodeDrbd(TestLUClusterVerifyGroupMethods):
1686
  def setUp(self):
1687
    super(TestLUClusterVerifyGroupVerifyNodeDrbd, self).setUp()
1688

    
1689
    self.node1 = self.cfg.AddNewNode()
1690
    self.node2 = self.cfg.AddNewNode()
1691
    self.inst = self.cfg.AddNewInstance(
1692
      disks=[self.cfg.CreateDisk(dev_type=constants.DT_DRBD8,
1693
                                 primary_node=self.node1,
1694
                                 secondary_node=self.node2)],
1695
      admin_state=constants.ADMINST_UP)
1696

    
1697
  @withLockedLU
1698
  def testNoDrbdHelper(self, lu):
1699
    lu._VerifyNodeDrbd(self.master, {}, self.cfg.GetAllInstancesInfo(), None,
1700
                       self.cfg.ComputeDRBDMap())
1701
    self.mcpu.assertLogIsEmpty()
1702

    
1703
  @withLockedLU
1704
  def testDrbdHelperInvalidNodeResult(self, lu):
1705
    for ndata, expected in [({}, "no drbd usermode helper returned"),
1706
                            ({constants.NV_DRBDHELPER: (False, "")},
1707
                             "drbd usermode helper check unsuccessful"),
1708
                            ({constants.NV_DRBDHELPER: (True, "/bin/false")},
1709
                             "wrong drbd usermode helper")]:
1710
      self.mcpu.ClearLogMessages()
1711
      lu._VerifyNodeDrbd(self.master, ndata, self.cfg.GetAllInstancesInfo(),
1712
                         "/bin/true", self.cfg.ComputeDRBDMap())
1713
      self.mcpu.assertLogContainsRegex(expected)
1714

    
1715
  @withLockedLU
1716
  def testNoNodeResult(self, lu):
1717
    lu._VerifyNodeDrbd(self.node1, {}, self.cfg.GetAllInstancesInfo(),
1718
                         None, self.cfg.ComputeDRBDMap())
1719
    self.mcpu.assertLogContainsRegex("drbd minor 1 of .* is not active")
1720

    
1721
  @withLockedLU
1722
  def testInvalidNodeResult(self, lu):
1723
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: ""},
1724
                       self.cfg.GetAllInstancesInfo(), None,
1725
                       self.cfg.ComputeDRBDMap())
1726
    self.mcpu.assertLogContainsRegex("cannot parse drbd status file")
1727

    
1728
  @withLockedLU
1729
  def testWrongMinorInUse(self, lu):
1730
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: [2]},
1731
                       self.cfg.GetAllInstancesInfo(), None,
1732
                       self.cfg.ComputeDRBDMap())
1733
    self.mcpu.assertLogContainsRegex("drbd minor 1 of .* is not active")
1734
    self.mcpu.assertLogContainsRegex("unallocated drbd minor 2 is in use")
1735

    
1736
  @withLockedLU
1737
  def testValidResult(self, lu):
1738
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: [1]},
1739
                       self.cfg.GetAllInstancesInfo(), None,
1740
                       self.cfg.ComputeDRBDMap())
1741
    self.mcpu.assertLogIsEmpty()
1742

    
1743

    
1744
class TestLUClusterVerifyGroupVerifyNodeOs(TestLUClusterVerifyGroupMethods):
1745
  @withLockedLU
1746
  def testUpdateNodeOsInvalidNodeResult(self, lu):
1747
    for ndata in [{}, {constants.NV_OSLIST: ""}, {constants.NV_OSLIST: [""]},
1748
                  {constants.NV_OSLIST: [["1", "2"]]}]:
1749
      self.mcpu.ClearLogMessages()
1750
      nimage = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1751
      lu._UpdateNodeOS(self.master, ndata, nimage)
1752
      self.mcpu.assertLogContainsRegex("node hasn't returned valid OS data")
1753

    
1754
  @withLockedLU
1755
  def testUpdateNodeOsValidNodeResult(self, lu):
1756
    ndata = {
1757
      constants.NV_OSLIST: [
1758
        ["mock_OS", "/mocked/path", True, "", ["default"], [],
1759
         [constants.OS_API_V20]],
1760
        ["Another_Mock", "/random", True, "", ["var1", "var2"],
1761
         [{"param1": "val1"}, {"param2": "val2"}], constants.OS_API_VERSIONS]
1762
      ]
1763
    }
1764
    nimage = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1765
    lu._UpdateNodeOS(self.master, ndata, nimage)
1766
    self.mcpu.assertLogIsEmpty()
1767

    
1768
  @withLockedLU
1769
  def testVerifyNodeOs(self, lu):
1770
    node = self.cfg.AddNewNode()
1771
    nimg_root = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1772
    nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=node.uuid)
1773

    
1774
    nimg_root.os_fail = False
1775
    nimg_root.oslist = {
1776
      "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1777
                   set([constants.OS_API_V20]))],
1778
      "broken_base_os": [("/broken", False, "", set(), set(),
1779
                         set([constants.OS_API_V20]))],
1780
      "only_on_root": [("/random", True, "", set(), set(), set())],
1781
      "diffing_os": [("/pinky", True, "", set(["var1", "var2"]),
1782
                      set([("param1", "val1"), ("param2", "val2")]),
1783
                      set([constants.OS_API_V20]))]
1784
    }
1785
    nimg.os_fail = False
1786
    nimg.oslist = {
1787
      "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1788
                   set([constants.OS_API_V20]))],
1789
      "only_on_test": [("/random", True, "", set(), set(), set())],
1790
      "diffing_os": [("/bunny", True, "", set(["var1", "var3"]),
1791
                      set([("param1", "val1"), ("param3", "val3")]),
1792
                      set([constants.OS_API_V15]))],
1793
      "broken_os": [("/broken", False, "", set(), set(),
1794
                     set([constants.OS_API_V20]))],
1795
      "multi_entries": [
1796
        ("/multi1", True, "", set(), set(), set([constants.OS_API_V20])),
1797
        ("/multi2", True, "", set(), set(), set([constants.OS_API_V20]))]
1798
    }
1799

    
1800
    lu._VerifyNodeOS(node, nimg, nimg_root)
1801

    
1802
    expected_msgs = [
1803
      "Extra OS only_on_test not present on reference node",
1804
      "OSes present on reference node .* but missing on this node:" +
1805
        " only_on_root",
1806
      "OS API version for diffing_os differs",
1807
      "OS variants list for diffing_os differs",
1808
      "OS parameters for diffing_os differs",
1809
      "Invalid OS broken_os",
1810
      "Extra OS broken_os not present on reference node",
1811
      "OS 'multi_entries' has multiple entries",
1812
      "Extra OS multi_entries not present on reference node"
1813
    ]
1814

    
1815
    self.assertEqual(len(expected_msgs), len(self.mcpu.GetLogMessages()))
1816
    for expected_msg in expected_msgs:
1817
      self.mcpu.assertLogContainsRegex(expected_msg)
1818

    
1819

    
1820
class TestLUClusterVerifyGroupVerifyAcceptedFileStoragePaths(
1821
  TestLUClusterVerifyGroupMethods):
1822
  @withLockedLU
1823
  def testNotMaster(self, lu):
1824
    lu._VerifyAcceptedFileStoragePaths(self.master, {}, False)
1825
    self.mcpu.assertLogIsEmpty()
1826

    
1827
  @withLockedLU
1828
  def testNotMasterButRetunedValue(self, lu):
1829
    lu._VerifyAcceptedFileStoragePaths(
1830
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: []}, False)
1831
    self.mcpu.assertLogContainsRegex(
1832
      "Node should not have returned forbidden file storage paths")
1833

    
1834
  @withLockedLU
1835
  def testMasterInvalidNodeResult(self, lu):
1836
    lu._VerifyAcceptedFileStoragePaths(self.master, {}, True)
1837
    self.mcpu.assertLogContainsRegex(
1838
      "Node did not return forbidden file storage paths")
1839

    
1840
  @withLockedLU
1841
  def testMasterForbiddenPaths(self, lu):
1842
    lu._VerifyAcceptedFileStoragePaths(
1843
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: ["/forbidden"]}, True)
1844
    self.mcpu.assertLogContainsRegex("Found forbidden file storage paths")
1845

    
1846
  @withLockedLU
1847
  def testMasterSuccess(self, lu):
1848
    lu._VerifyAcceptedFileStoragePaths(
1849
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: []}, True)
1850
    self.mcpu.assertLogIsEmpty()
1851

    
1852

    
1853
class TestLUClusterVerifyGroupVerifyStoragePaths(
1854
  TestLUClusterVerifyGroupMethods):
1855
  @withLockedLU
1856
  def testVerifyFileStoragePathsSuccess(self, lu):
1857
    lu._VerifyFileStoragePaths(self.master, {})
1858
    self.mcpu.assertLogIsEmpty()
1859

    
1860
  @withLockedLU
1861
  def testVerifyFileStoragePathsFailure(self, lu):
1862
    lu._VerifyFileStoragePaths(self.master,
1863
                               {constants.NV_FILE_STORAGE_PATH: "/fail/path"})
1864
    self.mcpu.assertLogContainsRegex(
1865
      "The configured file storage path is unusable")
1866

    
1867
  @withLockedLU
1868
  def testVerifySharedFileStoragePathsSuccess(self, lu):
1869
    lu._VerifySharedFileStoragePaths(self.master, {})
1870
    self.mcpu.assertLogIsEmpty()
1871

    
1872
  @withLockedLU
1873
  def testVerifySharedFileStoragePathsFailure(self, lu):
1874
    lu._VerifySharedFileStoragePaths(
1875
      self.master, {constants.NV_SHARED_FILE_STORAGE_PATH: "/fail/path"})
1876
    self.mcpu.assertLogContainsRegex(
1877
      "The configured sharedfile storage path is unusable")
1878

    
1879

    
1880
class TestLUClusterVerifyGroupVerifyOob(TestLUClusterVerifyGroupMethods):
1881
  @withLockedLU
1882
  def testEmptyResult(self, lu):
1883
    lu._VerifyOob(self.master, {})
1884
    self.mcpu.assertLogIsEmpty()
1885

    
1886
  @withLockedLU
1887
  def testErrorResults(self, lu):
1888
    lu._VerifyOob(self.master, {constants.NV_OOB_PATHS: ["path1", "path2"]})
1889
    self.mcpu.assertLogContainsRegex("path1")
1890
    self.mcpu.assertLogContainsRegex("path2")
1891

    
1892

    
1893
class TestLUClusterVerifyGroupUpdateNodeVolumes(
1894
  TestLUClusterVerifyGroupMethods):
1895
  def setUp(self):
1896
    super(TestLUClusterVerifyGroupUpdateNodeVolumes, self).setUp()
1897
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1898

    
1899
  @withLockedLU
1900
  def testNoVgName(self, lu):
1901
    lu._UpdateNodeVolumes(self.master, {}, self.nimg, None)
1902
    self.mcpu.assertLogIsEmpty()
1903
    self.assertTrue(self.nimg.lvm_fail)
1904

    
1905
  @withLockedLU
1906
  def testErrorMessage(self, lu):
1907
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: "mock error"},
1908
                          self.nimg, "mock_vg")
1909
    self.mcpu.assertLogContainsRegex("LVM problem on node: mock error")
1910
    self.assertTrue(self.nimg.lvm_fail)
1911

    
1912
  @withLockedLU
1913
  def testInvalidNodeResult(self, lu):
1914
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: [1, 2, 3]},
1915
                          self.nimg, "mock_vg")
1916
    self.mcpu.assertLogContainsRegex("rpc call to node failed")
1917
    self.assertTrue(self.nimg.lvm_fail)
1918

    
1919
  @withLockedLU
1920
  def testValidNodeResult(self, lu):
1921
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: {}},
1922
                          self.nimg, "mock_vg")
1923
    self.mcpu.assertLogIsEmpty()
1924
    self.assertFalse(self.nimg.lvm_fail)
1925

    
1926

    
1927
class TestLUClusterVerifyGroupUpdateNodeInstances(
1928
  TestLUClusterVerifyGroupMethods):
1929
  def setUp(self):
1930
    super(TestLUClusterVerifyGroupUpdateNodeInstances, self).setUp()
1931
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1932

    
1933
  @withLockedLU
1934
  def testInvalidNodeResult(self, lu):
1935
    lu._UpdateNodeInstances(self.master, {}, self.nimg)
1936
    self.mcpu.assertLogContainsRegex("rpc call to node failed")
1937

    
1938
  @withLockedLU
1939
  def testValidNodeResult(self, lu):
1940
    inst = self.cfg.AddNewInstance()
1941
    lu._UpdateNodeInstances(self.master,
1942
                            {constants.NV_INSTANCELIST: [inst.name]},
1943
                            self.nimg)
1944
    self.mcpu.assertLogIsEmpty()
1945

    
1946

    
1947
class TestLUClusterVerifyGroupUpdateNodeInfo(TestLUClusterVerifyGroupMethods):
1948
  def setUp(self):
1949
    super(TestLUClusterVerifyGroupUpdateNodeInfo, self).setUp()
1950
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1951
    self.valid_hvresult = {constants.NV_HVINFO: {"memory_free": 1024}}
1952

    
1953
  @withLockedLU
1954
  def testInvalidHvNodeResult(self, lu):
1955
    for ndata in [{}, {constants.NV_HVINFO: ""}]:
1956
      self.mcpu.ClearLogMessages()
1957
      lu._UpdateNodeInfo(self.master, ndata, self.nimg, None)
1958
      self.mcpu.assertLogContainsRegex("rpc call to node failed")
1959

    
1960
  @withLockedLU
1961
  def testInvalidMemoryFreeHvNodeResult(self, lu):
1962
    lu._UpdateNodeInfo(self.master,
1963
                       {constants.NV_HVINFO: {"memory_free": "abc"}},
1964
                       self.nimg, None)
1965
    self.mcpu.assertLogContainsRegex(
1966
      "node returned invalid nodeinfo, check hypervisor")
1967

    
1968
  @withLockedLU
1969
  def testValidHvNodeResult(self, lu):
1970
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, None)
1971
    self.mcpu.assertLogIsEmpty()
1972

    
1973
  @withLockedLU
1974
  def testInvalidVgNodeResult(self, lu):
1975
    for vgdata in [[], ""]:
1976
      self.mcpu.ClearLogMessages()
1977
      ndata = {constants.NV_VGLIST: vgdata}
1978
      ndata.update(self.valid_hvresult)
1979
      lu._UpdateNodeInfo(self.master, ndata, self.nimg, "mock_vg")
1980
      self.mcpu.assertLogContainsRegex(
1981
        "node didn't return data for the volume group 'mock_vg'")
1982

    
1983
  @withLockedLU
1984
  def testInvalidDiskFreeVgNodeResult(self, lu):
1985
    self.valid_hvresult.update({
1986
      constants.NV_VGLIST: {"mock_vg": "abc"}
1987
    })
1988
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, "mock_vg")
1989
    self.mcpu.assertLogContainsRegex(
1990
      "node returned invalid LVM info, check LVM status")
1991

    
1992
  @withLockedLU
1993
  def testValidVgNodeResult(self, lu):
1994
    self.valid_hvresult.update({
1995
      constants.NV_VGLIST: {"mock_vg": 10000}
1996
    })
1997
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, "mock_vg")
1998
    self.mcpu.assertLogIsEmpty()
1999

    
2000

    
2001
class TestLUClusterVerifyGroupCollectDiskInfo(TestLUClusterVerifyGroupMethods):
2002
  def setUp(self):
2003
    super(TestLUClusterVerifyGroupCollectDiskInfo, self).setUp()
2004

    
2005
    self.node1 = self.cfg.AddNewNode()
2006
    self.node2 = self.cfg.AddNewNode()
2007
    self.node3 = self.cfg.AddNewNode()
2008

    
2009
    self.diskless_inst = \
2010
      self.cfg.AddNewInstance(primary_node=self.node1,
2011
                              disk_template=constants.DT_DISKLESS)
2012
    self.plain_inst = \
2013
      self.cfg.AddNewInstance(primary_node=self.node2,
2014
                              disk_template=constants.DT_PLAIN)
2015
    self.drbd_inst = \
2016
      self.cfg.AddNewInstance(primary_node=self.node3,
2017
                              secondary_node=self.node2,
2018
                              disk_template=constants.DT_DRBD8)
2019

    
2020
    self.node1_img = cluster.LUClusterVerifyGroup.NodeImage(
2021
                       uuid=self.node1.uuid)
2022
    self.node1_img.pinst = [self.diskless_inst.uuid]
2023
    self.node1_img.sinst = []
2024
    self.node2_img = cluster.LUClusterVerifyGroup.NodeImage(
2025
                       uuid=self.node2.uuid)
2026
    self.node2_img.pinst = [self.plain_inst.uuid]
2027
    self.node2_img.sinst = [self.drbd_inst.uuid]
2028
    self.node3_img = cluster.LUClusterVerifyGroup.NodeImage(
2029
                       uuid=self.node3.uuid)
2030
    self.node3_img.pinst = [self.drbd_inst.uuid]
2031
    self.node3_img.sinst = []
2032

    
2033
    self.node_images = {
2034
      self.node1.uuid: self.node1_img,
2035
      self.node2.uuid: self.node2_img,
2036
      self.node3.uuid: self.node3_img
2037
    }
2038

    
2039
    self.node_uuids = [self.node1.uuid, self.node2.uuid, self.node3.uuid]
2040

    
2041
  @withLockedLU
2042
  def testSuccessfulRun(self, lu):
2043
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
2044
      RpcResultsBuilder() \
2045
        .AddSuccessfulNode(self.node2, [(True, ""), (True, "")]) \
2046
        .AddSuccessfulNode(self.node3, [(True, "")]) \
2047
        .Build()
2048

    
2049
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
2050
                        self.cfg.GetAllInstancesInfo())
2051

    
2052
    self.mcpu.assertLogIsEmpty()
2053

    
2054
  @withLockedLU
2055
  def testOfflineAndFailingNodes(self, lu):
2056
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
2057
      RpcResultsBuilder() \
2058
        .AddOfflineNode(self.node2) \
2059
        .AddFailedNode(self.node3) \
2060
        .Build()
2061

    
2062
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
2063
                        self.cfg.GetAllInstancesInfo())
2064

    
2065
    self.mcpu.assertLogContainsRegex("while getting disk information")
2066

    
2067
  @withLockedLU
2068
  def testInvalidNodeResult(self, lu):
2069
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
2070
      RpcResultsBuilder() \
2071
        .AddSuccessfulNode(self.node2, [(True,), (False,)]) \
2072
        .AddSuccessfulNode(self.node3, [""]) \
2073
        .Build()
2074

    
2075
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
2076
                        self.cfg.GetAllInstancesInfo())
2077
    # logging is not performed through mcpu
2078
    self.mcpu.assertLogIsEmpty()
2079

    
2080

    
2081
class TestLUClusterVerifyGroupHooksCallBack(TestLUClusterVerifyGroupMethods):
2082
  def setUp(self):
2083
    super(TestLUClusterVerifyGroupHooksCallBack, self).setUp()
2084

    
2085
    self.feedback_fn = lambda _: None
2086

    
2087
  def PrepareLU(self, lu):
2088
    super(TestLUClusterVerifyGroupHooksCallBack, self).PrepareLU(lu)
2089

    
2090
    lu.my_node_uuids = list(self.cfg.GetAllNodesInfo().keys())
2091

    
2092
  @withLockedLU
2093
  def testEmptyGroup(self, lu):
2094
    lu.my_node_uuids = []
2095
    lu.HooksCallBack(constants.HOOKS_PHASE_POST, None, self.feedback_fn, None)
2096

    
2097
  @withLockedLU
2098
  def testFailedResult(self, lu):
2099
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2100
                     RpcResultsBuilder(use_node_names=True)
2101
                       .AddFailedNode(self.master).Build(),
2102
                     self.feedback_fn,
2103
                     None)
2104
    self.mcpu.assertLogContainsRegex("Communication failure in hooks execution")
2105

    
2106
  @withLockedLU
2107
  def testOfflineNode(self, lu):
2108
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2109
                     RpcResultsBuilder(use_node_names=True)
2110
                       .AddOfflineNode(self.master).Build(),
2111
                     self.feedback_fn,
2112
                     None)
2113

    
2114
  @withLockedLU
2115
  def testValidResult(self, lu):
2116
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2117
                     RpcResultsBuilder(use_node_names=True)
2118
                       .AddSuccessfulNode(self.master,
2119
                                          [("mock_script",
2120
                                            constants.HKR_SUCCESS,
2121
                                            "mock output")])
2122
                       .Build(),
2123
                     self.feedback_fn,
2124
                     None)
2125

    
2126
  @withLockedLU
2127
  def testFailedScriptResult(self, lu):
2128
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2129
                     RpcResultsBuilder(use_node_names=True)
2130
                       .AddSuccessfulNode(self.master,
2131
                                          [("mock_script",
2132
                                            constants.HKR_FAIL,
2133
                                            "mock output")])
2134
                       .Build(),
2135
                     self.feedback_fn,
2136
                     None)
2137
    self.mcpu.assertLogContainsRegex("Script mock_script failed")
2138

    
2139

    
2140
class TestLUClusterVerifyDisks(CmdlibTestCase):
2141
  def testVerifyDisks(self):
2142
    op = opcodes.OpClusterVerifyDisks()
2143
    result = self.ExecOpCode(op)
2144

    
2145
    self.assertEqual(1, len(result["jobs"]))
2146

    
2147

    
2148
if __name__ == "__main__":
2149
  testutils.GanetiTestProgram()