Statistics
| Branch: | Tag: | Revision:

root / test / py / cmdlib / cluster_unittest.py @ 1583d0e4

History | View | Annotate | Download (70.7 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 = "1.2.3.4"
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.LD_LV):
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.LD_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.LD_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=0xFFFF0000)
423
    self.ExecOpCode(op)
424
    self.assertEqual(0xFFFF0000, 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
      self.ResetMocks()
430
      op = opcodes.OpClusterSetParams(diskparams=diskparams)
431
      self.ExecOpCodeExpectOpPrereqError(op, "verify diskparams")
432

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

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

    
447
  def testUnsetDrbdHelperWithDrbdDisks(self):
448
    self.cfg.AddNewInstance(disks=[
449
      self.cfg.CreateDisk(dev_type=constants.LD_DRBD8, create_nodes=True)])
450
    op = opcodes.OpClusterSetParams(drbd_helper="")
451
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable drbd helper")
452

    
453
  def testFileStorageDir(self):
454
    op = opcodes.OpClusterSetParams(file_storage_dir="/random/path")
455
    self.ExecOpCode(op)
456

    
457
  def testSetFileStorageDirToCurrentValue(self):
458
    op = opcodes.OpClusterSetParams(
459
           file_storage_dir=self.cluster.file_storage_dir)
460
    self.ExecOpCode(op)
461

    
462
    self.mcpu.assertLogContainsRegex("file storage dir already set to value")
463

    
464
  def testValidDrbdHelper(self):
465
    node1 = self.cfg.AddNewNode()
466
    node1.offline = True
467
    self.rpc.call_drbd_helper.return_value = \
468
      self.RpcResultsBuilder() \
469
        .AddSuccessfulNode(self.master, "/bin/true") \
470
        .AddOfflineNode(node1) \
471
        .Build()
472
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
473
    self.ExecOpCode(op)
474
    self.mcpu.assertLogContainsRegex("Not checking drbd helper on offline node")
475

    
476
  def testDrbdHelperFailingNode(self):
477
    self.rpc.call_drbd_helper.return_value = \
478
      self.RpcResultsBuilder() \
479
        .AddFailedNode(self.master) \
480
        .Build()
481
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
482
    self.ExecOpCodeExpectOpPrereqError(op, "Error checking drbd helper")
483

    
484
  def testInvalidDrbdHelper(self):
485
    self.rpc.call_drbd_helper.return_value = \
486
      self.RpcResultsBuilder() \
487
        .AddSuccessfulNode(self.master, "/bin/false") \
488
        .Build()
489
    op = opcodes.OpClusterSetParams(drbd_helper="/bin/true")
490
    self.ExecOpCodeExpectOpPrereqError(op, "drbd helper is /bin/false")
491

    
492
  def testDrbdHelperWithoutDrbdDiskTemplate(self):
493
    drbd_helper = "/bin/random_helper"
494
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
495
    self.rpc.call_drbd_helper.return_value = \
496
      self.RpcResultsBuilder() \
497
        .AddSuccessfulNode(self.master, drbd_helper) \
498
        .Build()
499
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
500
    self.ExecOpCode(op)
501

    
502
    self.mcpu.assertLogContainsRegex("but did not enable")
503

    
504
  def testResetDrbdHelper(self):
505
    drbd_helper = ""
506
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
507
    op = opcodes.OpClusterSetParams(drbd_helper=drbd_helper)
508
    self.ExecOpCode(op)
509

    
510
    self.assertEqual(None, self.cluster.drbd_usermode_helper)
511

    
512
  def testBeparams(self):
513
    beparams = {constants.BE_VCPUS: 32}
514
    op = opcodes.OpClusterSetParams(beparams=beparams)
515
    self.ExecOpCode(op)
516
    self.assertEqual(32, self.cluster
517
                           .beparams[constants.PP_DEFAULT][constants.BE_VCPUS])
518

    
519
  def testNdparams(self):
520
    ndparams = {constants.ND_EXCLUSIVE_STORAGE: True}
521
    op = opcodes.OpClusterSetParams(ndparams=ndparams)
522
    self.ExecOpCode(op)
523
    self.assertEqual(True, self.cluster
524
                             .ndparams[constants.ND_EXCLUSIVE_STORAGE])
525

    
526
  def testNdparamsResetOobProgram(self):
527
    ndparams = {constants.ND_OOB_PROGRAM: ""}
528
    op = opcodes.OpClusterSetParams(ndparams=ndparams)
529
    self.ExecOpCode(op)
530
    self.assertEqual(constants.NDC_DEFAULTS[constants.ND_OOB_PROGRAM],
531
                     self.cluster.ndparams[constants.ND_OOB_PROGRAM])
532

    
533
  def testHvState(self):
534
    hv_state = {constants.HT_FAKE: {constants.HVST_CPU_TOTAL: 8}}
535
    op = opcodes.OpClusterSetParams(hv_state=hv_state)
536
    self.ExecOpCode(op)
537
    self.assertEqual(8, self.cluster.hv_state_static
538
                          [constants.HT_FAKE][constants.HVST_CPU_TOTAL])
539

    
540
  def testDiskState(self):
541
    disk_state = {
542
      constants.LD_LV: {
543
        "mock_vg": {constants.DS_DISK_TOTAL: 10}
544
      }
545
    }
546
    op = opcodes.OpClusterSetParams(disk_state=disk_state)
547
    self.ExecOpCode(op)
548
    self.assertEqual(10, self.cluster
549
                           .disk_state_static[constants.LD_LV]["mock_vg"]
550
                             [constants.DS_DISK_TOTAL])
551

    
552
  def testDefaultIPolicy(self):
553
    ipolicy = constants.IPOLICY_DEFAULTS
554
    op = opcodes.OpClusterSetParams(ipolicy=ipolicy)
555
    self.ExecOpCode(op)
556

    
557
  def testIPolicyNewViolation(self):
558
    import ganeti.constants as C
559
    ipolicy = C.IPOLICY_DEFAULTS
560
    ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MIN][C.ISPEC_MEM_SIZE] = 128
561
    ipolicy[C.ISPECS_MINMAX][0][C.ISPECS_MAX][C.ISPEC_MEM_SIZE] = 128
562

    
563
    self.cfg.AddNewInstance(beparams={C.BE_MINMEM: 512, C.BE_MAXMEM: 512})
564
    op = opcodes.OpClusterSetParams(ipolicy=ipolicy)
565
    self.ExecOpCode(op)
566

    
567
    self.mcpu.assertLogContainsRegex("instances violate them")
568

    
569
  def testNicparamsNoInstance(self):
570
    nicparams = {
571
      constants.NIC_LINK: "mock_bridge"
572
    }
573
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
574
    self.ExecOpCode(op)
575

    
576
    self.assertEqual("mock_bridge",
577
                     self.cluster.nicparams
578
                       [constants.PP_DEFAULT][constants.NIC_LINK])
579

    
580
  def testNicparamsInvalidConf(self):
581
    nicparams = {
582
      constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
583
      constants.NIC_LINK: ""
584
    }
585
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
586
    self.ExecOpCodeExpectException(op, errors.ConfigurationError, "NIC link")
587

    
588
  def testNicparamsInvalidInstanceConf(self):
589
    nicparams = {
590
      constants.NIC_MODE: constants.NIC_MODE_BRIDGED,
591
      constants.NIC_LINK: "mock_bridge"
592
    }
593
    self.cfg.AddNewInstance(nics=[
594
      self.cfg.CreateNic(nicparams={constants.NIC_LINK: None})])
595
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
596
    self.ExecOpCodeExpectOpPrereqError(op, "Missing bridged NIC link")
597

    
598
  def testNicparamsMissingIp(self):
599
    nicparams = {
600
      constants.NIC_MODE: constants.NIC_MODE_ROUTED
601
    }
602
    self.cfg.AddNewInstance()
603
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
604
    self.ExecOpCodeExpectOpPrereqError(op, "routed NIC with no ip address")
605

    
606
  def testNicparamsWithInstance(self):
607
    nicparams = {
608
      constants.NIC_LINK: "mock_bridge"
609
    }
610
    self.cfg.AddNewInstance()
611
    op = opcodes.OpClusterSetParams(nicparams=nicparams)
612
    self.ExecOpCode(op)
613

    
614
  def testDefaultHvparams(self):
615
    hvparams = constants.HVC_DEFAULTS
616
    op = opcodes.OpClusterSetParams(hvparams=hvparams)
617
    self.ExecOpCode(op)
618

    
619
    self.assertEqual(hvparams, self.cluster.hvparams)
620

    
621
  def testMinimalHvparams(self):
622
    hvparams = {
623
      constants.HT_FAKE: {
624
        constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE
625
      }
626
    }
627
    self.cluster.hvparams = {}
628
    op = opcodes.OpClusterSetParams(hvparams=hvparams)
629
    self.ExecOpCode(op)
630

    
631
    self.assertEqual(hvparams, self.cluster.hvparams)
632

    
633
  def testOsHvp(self):
634
    os_hvp = {
635
      "mocked_os": {
636
        constants.HT_FAKE: {
637
          constants.HV_MIGRATION_MODE: constants.HT_MIGRATION_NONLIVE
638
        }
639
      },
640
      "other_os": constants.HVC_DEFAULTS
641
    }
642
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
643
    self.ExecOpCode(op)
644

    
645
    self.assertEqual(constants.HT_MIGRATION_NONLIVE,
646
                     self.cluster.os_hvp["mocked_os"][constants.HT_FAKE]
647
                       [constants.HV_MIGRATION_MODE])
648
    self.assertEqual(constants.HVC_DEFAULTS, self.cluster.os_hvp["other_os"])
649

    
650
  def testRemoveOsHvp(self):
651
    os_hvp = {"mocked_os": {constants.HT_FAKE: None}}
652
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
653
    self.ExecOpCode(op)
654

    
655
    assert constants.HT_FAKE not in self.cluster.os_hvp["mocked_os"]
656

    
657
  def testDefaultOsHvp(self):
658
    os_hvp = {"mocked_os": constants.HVC_DEFAULTS.copy()}
659
    self.cluster.os_hvp = {"mocked_os": {}}
660
    op = opcodes.OpClusterSetParams(os_hvp=os_hvp)
661
    self.ExecOpCode(op)
662

    
663
    self.assertEqual(os_hvp, self.cluster.os_hvp)
664

    
665
  def testOsparams(self):
666
    osparams = {
667
      "mocked_os": {
668
        "param1": "value1",
669
        "param2": None
670
      },
671
      "other_os": {
672
        "param1": None
673
      }
674
    }
675
    self.cluster.osparams = {"other_os": {"param1": "value1"}}
676
    op = opcodes.OpClusterSetParams(osparams=osparams)
677
    self.ExecOpCode(op)
678

    
679
    self.assertEqual({"mocked_os": {"param1": "value1"}}, self.cluster.osparams)
680

    
681
  def testEnabledHypervisors(self):
682
    enabled_hypervisors = [constants.HT_XEN_HVM, constants.HT_XEN_PVM]
683
    op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors)
684
    self.ExecOpCode(op)
685

    
686
    self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors)
687

    
688
  def testEnabledHypervisorsWithoutHypervisorParams(self):
689
    enabled_hypervisors = [constants.HT_FAKE]
690
    self.cluster.hvparams = {}
691
    op = opcodes.OpClusterSetParams(enabled_hypervisors=enabled_hypervisors)
692
    self.ExecOpCode(op)
693

    
694
    self.assertEqual(enabled_hypervisors, self.cluster.enabled_hypervisors)
695
    self.assertEqual(constants.HVC_DEFAULTS[constants.HT_FAKE],
696
                     self.cluster.hvparams[constants.HT_FAKE])
697

    
698
  @testutils.patch_object(utils, "FindFile")
699
  def testValidDefaultIallocator(self, find_file_mock):
700
    find_file_mock.return_value = "/random/path"
701
    default_iallocator = "/random/path"
702
    op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator)
703
    self.ExecOpCode(op)
704

    
705
    self.assertEqual(default_iallocator, self.cluster.default_iallocator)
706

    
707
  @testutils.patch_object(utils, "FindFile")
708
  def testInvalidDefaultIallocator(self, find_file_mock):
709
    find_file_mock.return_value = None
710
    default_iallocator = "/random/path"
711
    op = opcodes.OpClusterSetParams(default_iallocator=default_iallocator)
712
    self.ExecOpCodeExpectOpPrereqError(op, "Invalid default iallocator script")
713

    
714
  def testEnabledDiskTemplates(self):
715
    enabled_disk_templates = [constants.DT_DISKLESS, constants.DT_PLAIN]
716
    op = opcodes.OpClusterSetParams(
717
           enabled_disk_templates=enabled_disk_templates,
718
           ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
719
    self.ExecOpCode(op)
720

    
721
    self.assertEqual(enabled_disk_templates,
722
                     self.cluster.enabled_disk_templates)
723

    
724
  def testEnabledDiskTemplatesWithoutVgName(self):
725
    enabled_disk_templates = [constants.DT_PLAIN]
726
    self.cluster.volume_group_name = None
727
    op = opcodes.OpClusterSetParams(
728
           enabled_disk_templates=enabled_disk_templates)
729
    self.ExecOpCodeExpectOpPrereqError(op, "specify a volume group")
730

    
731
  def testDisableDiskTemplateWithExistingInstance(self):
732
    enabled_disk_templates = [constants.DT_DISKLESS]
733
    self.cfg.AddNewInstance(
734
      disks=[self.cfg.CreateDisk(dev_type=constants.LD_LV)])
735
    op = opcodes.OpClusterSetParams(
736
           enabled_disk_templates=enabled_disk_templates,
737
           ipolicy={constants.IPOLICY_DTS: enabled_disk_templates})
738
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot disable disk template")
739

    
740
  def testVgNameNoLvmDiskTemplateEnabled(self):
741
    vg_name = "test_vg"
742
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
743
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
744
    self.ExecOpCode(op)
745

    
746
    self.assertEqual(vg_name, self.cluster.volume_group_name)
747
    self.mcpu.assertLogIsEmpty()
748

    
749
  def testUnsetVgNameWithLvmDiskTemplateEnabled(self):
750
    vg_name = ""
751
    self.cluster.enabled_disk_templates = [constants.DT_PLAIN]
752
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
753
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group")
754

    
755
  def testUnsetVgNameWithLvmInstance(self):
756
    vg_name = ""
757
    self.cfg.AddNewInstance(
758
      disks=[self.cfg.CreateDisk(dev_type=constants.LD_LV)])
759
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
760
    self.ExecOpCodeExpectOpPrereqError(op, "Cannot unset volume group")
761

    
762
  def testUnsetVgNameWithNoLvmDiskTemplateEnabled(self):
763
    vg_name = ""
764
    self.cfg.SetEnabledDiskTemplates([constants.DT_DISKLESS])
765
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
766
    self.ExecOpCode(op)
767

    
768
    self.assertEqual(None, self.cluster.volume_group_name)
769

    
770
  def testVgNameToOldName(self):
771
    vg_name = self.cluster.volume_group_name
772
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
773
    self.ExecOpCode(op)
774

    
775
    self.mcpu.assertLogContainsRegex("already in desired state")
776

    
777
  def testVgNameWithFailingNode(self):
778
    vg_name = "test_vg"
779
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
780
    self.rpc.call_vg_list.return_value = \
781
      self.RpcResultsBuilder() \
782
        .AddFailedNode(self.master) \
783
        .Build()
784
    self.ExecOpCode(op)
785

    
786
    self.mcpu.assertLogContainsRegex("Error while gathering data on node")
787

    
788
  def testVgNameWithValidNode(self):
789
    vg_name = "test_vg"
790
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
791
    self.rpc.call_vg_list.return_value = \
792
      self.RpcResultsBuilder() \
793
        .AddSuccessfulNode(self.master, {vg_name: 1024 * 1024}) \
794
        .Build()
795
    self.ExecOpCode(op)
796

    
797
  def testVgNameWithTooSmallNode(self):
798
    vg_name = "test_vg"
799
    op = opcodes.OpClusterSetParams(vg_name=vg_name)
800
    self.rpc.call_vg_list.return_value = \
801
      self.RpcResultsBuilder() \
802
        .AddSuccessfulNode(self.master, {vg_name: 1}) \
803
        .Build()
804
    self.ExecOpCodeExpectOpPrereqError(op, "too small")
805

    
806
  def testMiscParameters(self):
807
    op = opcodes.OpClusterSetParams(candidate_pool_size=123,
808
                                    maintain_node_health=True,
809
                                    modify_etc_hosts=True,
810
                                    prealloc_wipe_disks=True,
811
                                    reserved_lvs=["/dev/mock_lv"],
812
                                    use_external_mip_script=True)
813
    self.ExecOpCode(op)
814

    
815
    self.mcpu.assertLogIsEmpty()
816
    self.assertEqual(123, self.cluster.candidate_pool_size)
817
    self.assertEqual(True, self.cluster.maintain_node_health)
818
    self.assertEqual(True, self.cluster.modify_etc_hosts)
819
    self.assertEqual(True, self.cluster.prealloc_wipe_disks)
820
    self.assertEqual(["/dev/mock_lv"], self.cluster.reserved_lvs)
821
    self.assertEqual(True, self.cluster.use_external_mip_script)
822

    
823
  def testAddHiddenOs(self):
824
    self.cluster.hidden_os = ["hidden1", "hidden2"]
825
    op = opcodes.OpClusterSetParams(hidden_os=[(constants.DDM_ADD, "hidden2"),
826
                                               (constants.DDM_ADD, "hidden3")])
827
    self.ExecOpCode(op)
828

    
829
    self.assertEqual(["hidden1", "hidden2", "hidden3"], self.cluster.hidden_os)
830
    self.mcpu.assertLogContainsRegex("OS hidden2 already")
831

    
832
  def testRemoveBlacklistedOs(self):
833
    self.cluster.blacklisted_os = ["blisted1", "blisted2"]
834
    op = opcodes.OpClusterSetParams(blacklisted_os=[
835
                                      (constants.DDM_REMOVE, "blisted2"),
836
                                      (constants.DDM_REMOVE, "blisted3")])
837
    self.ExecOpCode(op)
838

    
839
    self.assertEqual(["blisted1"], self.cluster.blacklisted_os)
840
    self.mcpu.assertLogContainsRegex("OS blisted3 not found")
841

    
842
  def testMasterNetdev(self):
843
    master_netdev = "test_dev"
844
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev)
845
    self.ExecOpCode(op)
846

    
847
    self.assertEqual(master_netdev, self.cluster.master_netdev)
848

    
849
  def testMasterNetdevFailNoForce(self):
850
    master_netdev = "test_dev"
851
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev)
852
    self.rpc.call_node_deactivate_master_ip.return_value = \
853
      self.RpcResultsBuilder() \
854
        .CreateFailedNodeResult(self.master)
855
    self.ExecOpCodeExpectOpExecError(op, "Could not disable the master ip")
856

    
857
  def testMasterNetdevFailForce(self):
858
    master_netdev = "test_dev"
859
    op = opcodes.OpClusterSetParams(master_netdev=master_netdev,
860
                                    force=True)
861
    self.rpc.call_node_deactivate_master_ip.return_value = \
862
      self.RpcResultsBuilder() \
863
        .CreateFailedNodeResult(self.master)
864
    self.ExecOpCode(op)
865

    
866
    self.mcpu.assertLogContainsRegex("Could not disable the master ip")
867

    
868

    
869
class TestLUClusterVerify(CmdlibTestCase):
870
  def testVerifyAllGroups(self):
871
    op = opcodes.OpClusterVerify()
872
    result = self.ExecOpCode(op)
873

    
874
    self.assertEqual(2, len(result["jobs"]))
875

    
876
  def testVerifyDefaultGroups(self):
877
    op = opcodes.OpClusterVerify(group_name="default")
878
    result = self.ExecOpCode(op)
879

    
880
    self.assertEqual(1, len(result["jobs"]))
881

    
882

    
883
class TestLUClusterVerifyConfig(CmdlibTestCase):
884

    
885
  def setUp(self):
886
    super(TestLUClusterVerifyConfig, self).setUp()
887

    
888
    self._load_cert_patcher = testutils \
889
      .patch_object(OpenSSL.crypto, "load_certificate")
890
    self._load_cert_mock = self._load_cert_patcher.start()
891
    self._verify_cert_patcher = testutils \
892
      .patch_object(utils, "VerifyX509Certificate")
893
    self._verify_cert_mock = self._verify_cert_patcher.start()
894
    self._read_file_patcher = testutils.patch_object(utils, "ReadFile")
895
    self._read_file_mock = self._read_file_patcher.start()
896
    self._can_read_patcher = testutils.patch_object(utils, "CanRead")
897
    self._can_read_mock = self._can_read_patcher.start()
898

    
899
    self._can_read_mock.return_value = True
900
    self._read_file_mock.return_value = True
901
    self._verify_cert_mock.return_value = (None, "")
902
    self._load_cert_mock.return_value = True
903

    
904
  def tearDown(self):
905
    super(TestLUClusterVerifyConfig, self).tearDown()
906

    
907
    self._can_read_patcher.stop()
908
    self._read_file_patcher.stop()
909
    self._verify_cert_patcher.stop()
910
    self._load_cert_patcher.stop()
911

    
912
  def testSuccessfulRun(self):
913
    self.cfg.AddNewInstance()
914
    op = opcodes.OpClusterVerifyConfig()
915
    result = self.ExecOpCode(op)
916

    
917
    self.assertTrue(result)
918

    
919
  def testDanglingNode(self):
920
    node = self.cfg.AddNewNode()
921
    self.cfg.AddNewInstance(primary_node=node)
922
    node.group = "invalid"
923
    op = opcodes.OpClusterVerifyConfig()
924
    result = self.ExecOpCode(op)
925

    
926
    self.mcpu.assertLogContainsRegex(
927
      "following nodes \(and their instances\) belong to a non existing group")
928
    self.assertFalse(result)
929

    
930
  def testDanglingInstance(self):
931
    inst = self.cfg.AddNewInstance()
932
    inst.primary_node = "invalid"
933
    op = opcodes.OpClusterVerifyConfig()
934
    result = self.ExecOpCode(op)
935

    
936
    self.mcpu.assertLogContainsRegex(
937
      "following instances have a non-existing primary-node")
938
    self.assertFalse(result)
939

    
940

    
941
class TestLUClusterVerifyGroup(CmdlibTestCase):
942
  def testEmptyNodeGroup(self):
943
    group = self.cfg.AddNewNodeGroup()
944
    op = opcodes.OpClusterVerifyGroup(group_name=group.name, verbose=True)
945

    
946
    result = self.ExecOpCode(op)
947

    
948
    self.assertTrue(result)
949
    self.mcpu.assertLogContainsRegex("Empty node group, skipping verification")
950

    
951
  def testSimpleInvocation(self):
952
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
953

    
954
    self.ExecOpCode(op)
955

    
956
  def testSimpleInvocationWithInstance(self):
957
    self.cfg.AddNewInstance(disks=[])
958
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
959

    
960
    self.ExecOpCode(op)
961

    
962
  def testGhostNode(self):
963
    group = self.cfg.AddNewNodeGroup()
964
    node = self.cfg.AddNewNode(group=group.uuid, offline=True)
965
    self.master.offline = True
966
    self.cfg.AddNewInstance(disk_template=constants.DT_DRBD8,
967
                            primary_node=self.master,
968
                            secondary_node=node)
969

    
970
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
971
      RpcResultsBuilder() \
972
        .AddOfflineNode(self.master) \
973
        .Build()
974

    
975
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
976

    
977
    self.ExecOpCode(op)
978

    
979
  def testValidRpcResult(self):
980
    self.cfg.AddNewInstance(disks=[])
981

    
982
    self.rpc.call_node_verify.return_value = \
983
      RpcResultsBuilder() \
984
        .AddSuccessfulNode(self.master, {}) \
985
        .Build()
986

    
987
    op = opcodes.OpClusterVerifyGroup(group_name="default", verbose=True)
988

    
989
    self.ExecOpCode(op)
990

    
991

    
992
class TestLUClusterVerifyGroupMethods(CmdlibTestCase):
993
  """Base class for testing individual methods in LUClusterVerifyGroup.
994

995
  """
996
  def setUp(self):
997
    super(TestLUClusterVerifyGroupMethods, self).setUp()
998
    self.op = opcodes.OpClusterVerifyGroup(group_name="default")
999

    
1000
  def PrepareLU(self, lu):
1001
    lu._exclusive_storage = False
1002
    lu.master_node = self.master_uuid
1003
    lu.group_info = self.group
1004
    cluster.LUClusterVerifyGroup.all_node_info = \
1005
      property(fget=lambda _: self.cfg.GetAllNodesInfo())
1006

    
1007

    
1008
class TestLUClusterVerifyGroupVerifyNode(TestLUClusterVerifyGroupMethods):
1009
  @withLockedLU
1010
  def testInvalidNodeResult(self, lu):
1011
    self.assertFalse(lu._VerifyNode(self.master, None))
1012
    self.assertFalse(lu._VerifyNode(self.master, ""))
1013

    
1014
  @withLockedLU
1015
  def testInvalidVersion(self, lu):
1016
    self.assertFalse(lu._VerifyNode(self.master, {"version": None}))
1017
    self.assertFalse(lu._VerifyNode(self.master, {"version": ""}))
1018
    self.assertFalse(lu._VerifyNode(self.master, {
1019
      "version": (constants.PROTOCOL_VERSION - 1, constants.RELEASE_VERSION)
1020
    }))
1021

    
1022
    self.mcpu.ClearLogMessages()
1023
    self.assertTrue(lu._VerifyNode(self.master, {
1024
      "version": (constants.PROTOCOL_VERSION, constants.RELEASE_VERSION + "x")
1025
    }))
1026
    self.mcpu.assertLogContainsRegex("software version mismatch")
1027

    
1028
  def _GetValidNodeResult(self, additional_fields):
1029
    ret = {
1030
      "version": (constants.PROTOCOL_VERSION, constants.RELEASE_VERSION),
1031
      constants.NV_NODESETUP: []
1032
    }
1033
    ret.update(additional_fields)
1034
    return ret
1035

    
1036
  @withLockedLU
1037
  def testHypervisor(self, lu):
1038
    lu._VerifyNode(self.master, self._GetValidNodeResult({
1039
      constants.NV_HYPERVISOR: {
1040
        constants.HT_XEN_PVM: None,
1041
        constants.HT_XEN_HVM: "mock error"
1042
      }
1043
    }))
1044
    self.mcpu.assertLogContainsRegex(constants.HT_XEN_HVM)
1045
    self.mcpu.assertLogContainsRegex("mock error")
1046

    
1047
  @withLockedLU
1048
  def testHvParams(self, lu):
1049
    lu._VerifyNode(self.master, self._GetValidNodeResult({
1050
      constants.NV_HVPARAMS: [("mock item", constants.HT_XEN_HVM, "mock error")]
1051
    }))
1052
    self.mcpu.assertLogContainsRegex(constants.HT_XEN_HVM)
1053
    self.mcpu.assertLogContainsRegex("mock item")
1054
    self.mcpu.assertLogContainsRegex("mock error")
1055

    
1056
  @withLockedLU
1057
  def testSuccessfulResult(self, lu):
1058
    self.assertTrue(lu._VerifyNode(self.master, self._GetValidNodeResult({})))
1059
    self.mcpu.assertLogIsEmpty()
1060

    
1061

    
1062
class TestLUClusterVerifyGroupVerifyNodeTime(TestLUClusterVerifyGroupMethods):
1063
  @withLockedLU
1064
  def testInvalidNodeResult(self, lu):
1065
    for ndata in [{}, {constants.NV_TIME: "invalid"}]:
1066
      self.mcpu.ClearLogMessages()
1067
      lu._VerifyNodeTime(self.master, ndata, None, None)
1068

    
1069
      self.mcpu.assertLogContainsRegex("Node returned invalid time")
1070

    
1071
  @withLockedLU
1072
  def testNodeDiverges(self, lu):
1073
    for ntime in [(0, 0), (2000, 0)]:
1074
      self.mcpu.ClearLogMessages()
1075
      lu._VerifyNodeTime(self.master, {constants.NV_TIME: ntime}, 1000, 1005)
1076

    
1077
      self.mcpu.assertLogContainsRegex("Node time diverges")
1078

    
1079
  @withLockedLU
1080
  def testSuccessfulResult(self, lu):
1081
    lu._VerifyNodeTime(self.master, {constants.NV_TIME: (0, 0)}, 0, 5)
1082
    self.mcpu.assertLogIsEmpty()
1083

    
1084

    
1085
class TestLUClusterVerifyGroupUpdateVerifyNodeLVM(
1086
        TestLUClusterVerifyGroupMethods):
1087
  def setUp(self):
1088
    super(TestLUClusterVerifyGroupUpdateVerifyNodeLVM, self).setUp()
1089
    self.VALID_NRESULT = {
1090
      constants.NV_VGLIST: {"mock_vg": 30000},
1091
      constants.NV_PVLIST: [
1092
        {
1093
          "name": "mock_pv",
1094
          "vg_name": "mock_vg",
1095
          "size": 5000,
1096
          "free": 2500,
1097
          "attributes": [],
1098
          "lv_list": []
1099
        }
1100
      ]
1101
    }
1102

    
1103
  @withLockedLU
1104
  def testNoVgName(self, lu):
1105
    lu._UpdateVerifyNodeLVM(self.master, {}, None, None)
1106
    self.mcpu.assertLogIsEmpty()
1107

    
1108
  @withLockedLU
1109
  def testEmptyNodeResult(self, lu):
1110
    lu._UpdateVerifyNodeLVM(self.master, {}, "mock_vg", None)
1111
    self.mcpu.assertLogContainsRegex("unable to check volume groups")
1112
    self.mcpu.assertLogContainsRegex("Can't get PV list from node")
1113

    
1114
  @withLockedLU
1115
  def testValidNodeResult(self, lu):
1116
    lu._UpdateVerifyNodeLVM(self.master, self.VALID_NRESULT, "mock_vg", None)
1117
    self.mcpu.assertLogIsEmpty()
1118

    
1119
  @withLockedLU
1120
  def testValidNodeResultExclusiveStorage(self, lu):
1121
    lu._exclusive_storage = True
1122
    lu._UpdateVerifyNodeLVM(self.master, self.VALID_NRESULT, "mock_vg",
1123
                            cluster.LUClusterVerifyGroup.NodeImage())
1124
    self.mcpu.assertLogIsEmpty()
1125

    
1126

    
1127
class TestLUClusterVerifyGroupVerifyGroupDRBDVersion(
1128
        TestLUClusterVerifyGroupMethods):
1129
  @withLockedLU
1130
  def testEmptyNodeResult(self, lu):
1131
    lu._VerifyGroupDRBDVersion({})
1132
    self.mcpu.assertLogIsEmpty()
1133

    
1134
  @withLockedLU
1135
  def testValidNodeResult(self, lu):
1136
    lu._VerifyGroupDRBDVersion(
1137
      RpcResultsBuilder()
1138
        .AddSuccessfulNode(self.master, {
1139
          constants.NV_DRBDVERSION: "8.3.0"
1140
        })
1141
        .Build())
1142
    self.mcpu.assertLogIsEmpty()
1143

    
1144
  @withLockedLU
1145
  def testDifferentVersions(self, lu):
1146
    node1 = self.cfg.AddNewNode()
1147
    lu._VerifyGroupDRBDVersion(
1148
      RpcResultsBuilder()
1149
        .AddSuccessfulNode(self.master, {
1150
          constants.NV_DRBDVERSION: "8.3.0"
1151
        })
1152
        .AddSuccessfulNode(node1, {
1153
          constants.NV_DRBDVERSION: "8.4.0"
1154
        })
1155
        .Build())
1156
    self.mcpu.assertLogContainsRegex("DRBD version mismatch: 8.3.0")
1157
    self.mcpu.assertLogContainsRegex("DRBD version mismatch: 8.4.0")
1158

    
1159

    
1160
class TestLUClusterVerifyGroupVerifyGroupLVM(TestLUClusterVerifyGroupMethods):
1161
  @withLockedLU
1162
  def testNoVgName(self, lu):
1163
    lu._VerifyGroupLVM(None, None)
1164
    self.mcpu.assertLogIsEmpty()
1165

    
1166
  @withLockedLU
1167
  def testNoExclusiveStorage(self, lu):
1168
    lu._VerifyGroupLVM(None, "mock_vg")
1169
    self.mcpu.assertLogIsEmpty()
1170

    
1171
  @withLockedLU
1172
  def testNoPvInfo(self, lu):
1173
    lu._exclusive_storage = True
1174
    nimg = cluster.LUClusterVerifyGroup.NodeImage()
1175
    lu._VerifyGroupLVM({self.master.uuid: nimg}, "mock_vg")
1176
    self.mcpu.assertLogIsEmpty()
1177

    
1178
  @withLockedLU
1179
  def testValidPvInfos(self, lu):
1180
    lu._exclusive_storage = True
1181
    node2 = self.cfg.AddNewNode()
1182
    nimg1 = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master.uuid)
1183
    nimg1.pv_min = 10000
1184
    nimg1.pv_max = 10010
1185
    nimg2 = cluster.LUClusterVerifyGroup.NodeImage(uuid=node2.uuid)
1186
    nimg2.pv_min = 9998
1187
    nimg2.pv_max = 10005
1188
    lu._VerifyGroupLVM({self.master.uuid: nimg1, node2.uuid: nimg2}, "mock_vg")
1189
    self.mcpu.assertLogIsEmpty()
1190

    
1191

    
1192
class TestLUClusterVerifyGroupVerifyNodeBridges(
1193
        TestLUClusterVerifyGroupMethods):
1194
  @withLockedLU
1195
  def testNoBridges(self, lu):
1196
    lu._VerifyNodeBridges(None, None, None)
1197
    self.mcpu.assertLogIsEmpty()
1198

    
1199
  @withLockedLU
1200
  def testInvalidBridges(self, lu):
1201
    for ndata in [{}, {constants.NV_BRIDGES: ""}]:
1202
      self.mcpu.ClearLogMessages()
1203
      lu._VerifyNodeBridges(self.master, ndata, ["mock_bridge"])
1204
      self.mcpu.assertLogContainsRegex("not return valid bridge information")
1205

    
1206
    self.mcpu.ClearLogMessages()
1207
    lu._VerifyNodeBridges(self.master, {constants.NV_BRIDGES: ["mock_bridge"]},
1208
                          ["mock_bridge"])
1209
    self.mcpu.assertLogContainsRegex("missing bridge")
1210

    
1211

    
1212
class TestLUClusterVerifyGroupVerifyNodeUserScripts(
1213
        TestLUClusterVerifyGroupMethods):
1214
  @withLockedLU
1215
  def testNoUserScripts(self, lu):
1216
    lu._VerifyNodeUserScripts(self.master, {})
1217
    self.mcpu.assertLogContainsRegex("did not return user scripts information")
1218

    
1219
  @withLockedLU
1220
  def testBrokenUserScripts(self, lu):
1221
    lu._VerifyNodeUserScripts(self.master,
1222
                              {constants.NV_USERSCRIPTS: ["script"]})
1223
    self.mcpu.assertLogContainsRegex("scripts not present or not executable")
1224

    
1225

    
1226
class TestLUClusterVerifyGroupVerifyNodeNetwork(
1227
        TestLUClusterVerifyGroupMethods):
1228

    
1229
  def setUp(self):
1230
    super(TestLUClusterVerifyGroupVerifyNodeNetwork, self).setUp()
1231
    self.VALID_NRESULT = {
1232
      constants.NV_NODELIST: {},
1233
      constants.NV_NODENETTEST: {},
1234
      constants.NV_MASTERIP: True
1235
    }
1236

    
1237
  @withLockedLU
1238
  def testEmptyNodeResult(self, lu):
1239
    lu._VerifyNodeNetwork(self.master, {})
1240
    self.mcpu.assertLogContainsRegex(
1241
      "node hasn't returned node ssh connectivity data")
1242
    self.mcpu.assertLogContainsRegex(
1243
      "node hasn't returned node tcp connectivity data")
1244
    self.mcpu.assertLogContainsRegex(
1245
      "node hasn't returned node master IP reachability data")
1246

    
1247
  @withLockedLU
1248
  def testValidResult(self, lu):
1249
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1250
    self.mcpu.assertLogIsEmpty()
1251

    
1252
  @withLockedLU
1253
  def testSshProblem(self, lu):
1254
    self.VALID_NRESULT.update({
1255
      constants.NV_NODELIST: {
1256
        "mock_node": "mock_error"
1257
      }
1258
    })
1259
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1260
    self.mcpu.assertLogContainsRegex("ssh communication with node 'mock_node'")
1261

    
1262
  @withLockedLU
1263
  def testTcpProblem(self, lu):
1264
    self.VALID_NRESULT.update({
1265
      constants.NV_NODENETTEST: {
1266
        "mock_node": "mock_error"
1267
      }
1268
    })
1269
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1270
    self.mcpu.assertLogContainsRegex("tcp communication with node 'mock_node'")
1271

    
1272
  @withLockedLU
1273
  def testMasterIpNotReachable(self, lu):
1274
    self.VALID_NRESULT.update({
1275
      constants.NV_MASTERIP: False
1276
    })
1277
    node1 = self.cfg.AddNewNode()
1278
    lu._VerifyNodeNetwork(self.master, self.VALID_NRESULT)
1279
    self.mcpu.assertLogContainsRegex(
1280
      "the master node cannot reach the master IP")
1281

    
1282
    self.mcpu.ClearLogMessages()
1283
    lu._VerifyNodeNetwork(node1, self.VALID_NRESULT)
1284
    self.mcpu.assertLogContainsRegex("cannot reach the master IP")
1285

    
1286

    
1287
class TestLUClusterVerifyGroupVerifyInstance(TestLUClusterVerifyGroupMethods):
1288
  def setUp(self):
1289
    super(TestLUClusterVerifyGroupVerifyInstance, self).setUp()
1290

    
1291
    self.node1 = self.cfg.AddNewNode()
1292
    self.drbd_inst = self.cfg.AddNewInstance(
1293
      disks=[self.cfg.CreateDisk(dev_type=constants.LD_DRBD8,
1294
                                 primary_node=self.master,
1295
                                 secondary_node=self.node1)])
1296
    self.running_inst = self.cfg.AddNewInstance(
1297
      admin_state=constants.ADMINST_UP, disks_active=True)
1298
    self.diskless_inst = self.cfg.AddNewInstance(disks=[])
1299

    
1300
    self.master_img = \
1301
      cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1302
    self.master_img.volumes = ["/".join(disk.logical_id)
1303
                               for inst in [self.running_inst,
1304
                                            self.diskless_inst]
1305
                               for disk in inst.disks]
1306
    self.master_img.volumes.extend(
1307
      ["/".join(disk.logical_id) for disk in self.drbd_inst.disks[0].children])
1308
    self.master_img.instances = [self.running_inst.uuid]
1309
    self.node1_img = \
1310
      cluster.LUClusterVerifyGroup.NodeImage(uuid=self.node1.uuid)
1311
    self.node1_img.volumes = \
1312
      ["/".join(disk.logical_id) for disk in self.drbd_inst.disks[0].children]
1313
    self.node_imgs = {
1314
      self.master_uuid: self.master_img,
1315
      self.node1.uuid: self.node1_img
1316
    }
1317
    self.diskstatus = {
1318
      self.master_uuid: [
1319
        (True, objects.BlockDevStatus(ldisk_status=constants.LDS_OKAY))
1320
        for _ in self.running_inst.disks
1321
      ]
1322
    }
1323

    
1324
  @withLockedLU
1325
  def testDisklessInst(self, lu):
1326
    lu._VerifyInstance(self.diskless_inst, self.node_imgs, {})
1327
    self.mcpu.assertLogIsEmpty()
1328

    
1329
  @withLockedLU
1330
  def testOfflineNode(self, lu):
1331
    self.master_img.offline = True
1332
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, {})
1333
    self.mcpu.assertLogIsEmpty()
1334

    
1335
  @withLockedLU
1336
  def testRunningOnOfflineNode(self, lu):
1337
    self.master_img.offline = True
1338
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1339
    self.mcpu.assertLogContainsRegex(
1340
      "instance is marked as running and lives on offline node")
1341

    
1342
  @withLockedLU
1343
  def testMissingVolume(self, lu):
1344
    self.master_img.volumes = []
1345
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1346
    self.mcpu.assertLogContainsRegex("volume .* missing")
1347

    
1348
  @withLockedLU
1349
  def testRunningInstanceOnWrongNode(self, lu):
1350
    self.master_img.instances = []
1351
    self.diskless_inst.admin_state = constants.ADMINST_UP
1352
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1353
    self.mcpu.assertLogContainsRegex("instance not running on its primary node")
1354

    
1355
  @withLockedLU
1356
  def testRunningInstanceOnRightNode(self, lu):
1357
    self.master_img.instances = [self.running_inst.uuid]
1358
    lu._VerifyInstance(self.running_inst, self.node_imgs, {})
1359
    self.mcpu.assertLogIsEmpty()
1360

    
1361
  @withLockedLU
1362
  def testValidDiskStatus(self, lu):
1363
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1364
    self.mcpu.assertLogIsEmpty()
1365

    
1366
  @withLockedLU
1367
  def testDegradedDiskStatus(self, lu):
1368
    self.diskstatus[self.master_uuid][0][1].is_degraded = True
1369
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1370
    self.mcpu.assertLogContainsRegex("instance .* is degraded")
1371

    
1372
  @withLockedLU
1373
  def testNotOkayDiskStatus(self, lu):
1374
    self.diskstatus[self.master_uuid][0][1].ldisk_status = constants.LDS_FAULTY
1375
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1376
    self.mcpu.assertLogContainsRegex("instance .* state is 'faulty'")
1377

    
1378
  @withLockedLU
1379
  def testExclusiveStorageWithInvalidInstance(self, lu):
1380
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
1381
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1382
    self.mcpu.assertLogContainsRegex(
1383
      "instance has template drbd, which is not supported")
1384

    
1385
  @withLockedLU
1386
  def testExclusiveStorageWithValidInstance(self, lu):
1387
    self.master.ndparams[constants.ND_EXCLUSIVE_STORAGE] = True
1388
    self.running_inst.disks[0].spindles = 1
1389
    lu._VerifyInstance(self.running_inst, self.node_imgs, self.diskstatus)
1390
    self.mcpu.assertLogIsEmpty()
1391

    
1392
  @withLockedLU
1393
  def testDrbdInTwoGroups(self, lu):
1394
    group = self.cfg.AddNewNodeGroup()
1395
    self.node1.group = group.uuid
1396
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1397
    self.mcpu.assertLogContainsRegex(
1398
      "instance has primary and secondary nodes in different groups")
1399

    
1400
  @withLockedLU
1401
  def testOfflineSecondary(self, lu):
1402
    self.node1_img.offline = True
1403
    lu._VerifyInstance(self.drbd_inst, self.node_imgs, self.diskstatus)
1404
    self.mcpu.assertLogContainsRegex("instance has offline secondary node\(s\)")
1405

    
1406

    
1407
class TestLUClusterVerifyGroupVerifyOrphanVolumes(
1408
        TestLUClusterVerifyGroupMethods):
1409
  @withLockedLU
1410
  def testOrphanedVolume(self, lu):
1411
    master_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1412
    master_img.volumes = ["mock_vg/disk_0", "mock_vg/disk_1", "mock_vg/disk_2"]
1413
    node_imgs = {
1414
      self.master_uuid: master_img
1415
    }
1416
    node_vol_should = {
1417
      self.master_uuid: ["mock_vg/disk_0"]
1418
    }
1419

    
1420
    lu._VerifyOrphanVolumes(node_vol_should, node_imgs,
1421
                            utils.FieldSet("mock_vg/disk_2"))
1422
    self.mcpu.assertLogContainsRegex("volume mock_vg/disk_1 is unknown")
1423
    self.mcpu.assertLogDoesNotContainRegex("volume mock_vg/disk_0 is unknown")
1424
    self.mcpu.assertLogDoesNotContainRegex("volume mock_vg/disk_2 is unknown")
1425

    
1426

    
1427
class TestLUClusterVerifyGroupVerifyNPlusOneMemory(
1428
        TestLUClusterVerifyGroupMethods):
1429
  @withLockedLU
1430
  def testN1Failure(self, lu):
1431
    group1 = self.cfg.AddNewNodeGroup()
1432

    
1433
    node1 = self.cfg.AddNewNode()
1434
    node2 = self.cfg.AddNewNode(group=group1)
1435
    node3 = self.cfg.AddNewNode()
1436

    
1437
    inst1 = self.cfg.AddNewInstance()
1438
    inst2 = self.cfg.AddNewInstance()
1439
    inst3 = self.cfg.AddNewInstance()
1440

    
1441
    node1_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node1.uuid)
1442
    node1_img.sbp = {
1443
      self.master_uuid: [inst1.uuid, inst2.uuid, inst3.uuid]
1444
    }
1445

    
1446
    node2_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node2.uuid)
1447

    
1448
    node3_img = cluster.LUClusterVerifyGroup.NodeImage(uuid=node3.uuid)
1449
    node3_img.offline = True
1450

    
1451
    node_imgs = {
1452
      node1.uuid: node1_img,
1453
      node2.uuid: node2_img,
1454
      node3.uuid: node3_img
1455
    }
1456

    
1457
    lu._VerifyNPlusOneMemory(node_imgs, self.cfg.GetAllInstancesInfo())
1458
    self.mcpu.assertLogContainsRegex(
1459
      "not enough memory to accomodate instance failovers")
1460

    
1461
    self.mcpu.ClearLogMessages()
1462
    node1_img.mfree = 1000
1463
    lu._VerifyNPlusOneMemory(node_imgs, self.cfg.GetAllInstancesInfo())
1464
    self.mcpu.assertLogIsEmpty()
1465

    
1466

    
1467
class TestLUClusterVerifyGroupVerifyFiles(TestLUClusterVerifyGroupMethods):
1468
  @withLockedLU
1469
  def test(self, lu):
1470
    node1 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1471
                                vm_capable=True)
1472
    node2 = self.cfg.AddNewNode(master_candidate=True, vm_capable=False)
1473
    node3 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1474
                                vm_capable=True)
1475
    node4 = self.cfg.AddNewNode(master_candidate=False, offline=False,
1476
                                vm_capable=True)
1477
    node5 = self.cfg.AddNewNode(master_candidate=False, offline=True)
1478

    
1479
    nodeinfo = [self.master, node1, node2, node3, node4, node5]
1480
    files_all = set([
1481
      pathutils.CLUSTER_DOMAIN_SECRET_FILE,
1482
      pathutils.RAPI_CERT_FILE,
1483
      pathutils.RAPI_USERS_FILE,
1484
      ])
1485
    files_opt = set([
1486
      pathutils.RAPI_USERS_FILE,
1487
      hv_xen.XL_CONFIG_FILE,
1488
      pathutils.VNC_PASSWORD_FILE,
1489
      ])
1490
    files_mc = set([
1491
      pathutils.CLUSTER_CONF_FILE,
1492
      ])
1493
    files_vm = set([
1494
      hv_xen.XEND_CONFIG_FILE,
1495
      hv_xen.XL_CONFIG_FILE,
1496
      pathutils.VNC_PASSWORD_FILE,
1497
      ])
1498
    nvinfo = RpcResultsBuilder() \
1499
      .AddSuccessfulNode(self.master, {
1500
        constants.NV_FILELIST: {
1501
          pathutils.CLUSTER_CONF_FILE: "82314f897f38b35f9dab2f7c6b1593e0",
1502
          pathutils.RAPI_CERT_FILE: "babbce8f387bc082228e544a2146fee4",
1503
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1504
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
1505
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
1506
        }}) \
1507
      .AddSuccessfulNode(node1, {
1508
        constants.NV_FILELIST: {
1509
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1510
          hv_xen.XEND_CONFIG_FILE: "b4a8a824ab3cac3d88839a9adeadf310",
1511
          }
1512
        }) \
1513
      .AddSuccessfulNode(node2, {
1514
        constants.NV_FILELIST: {
1515
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1516
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1517
          }
1518
        }) \
1519
      .AddSuccessfulNode(node3, {
1520
        constants.NV_FILELIST: {
1521
          pathutils.RAPI_CERT_FILE: "97f0356500e866387f4b84233848cc4a",
1522
          pathutils.CLUSTER_CONF_FILE: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
1523
          pathutils.CLUSTER_DOMAIN_SECRET_FILE: "cds-47b5b3f19202936bb4",
1524
          pathutils.RAPI_USERS_FILE: "rapiusers-ea3271e8d810ef3",
1525
          hv_xen.XL_CONFIG_FILE: "77935cee92afd26d162f9e525e3d49b9"
1526
          }
1527
        }) \
1528
      .AddSuccessfulNode(node4, {}) \
1529
      .AddOfflineNode(node5) \
1530
      .Build()
1531
    assert set(nvinfo.keys()) == set(map(operator.attrgetter("uuid"), nodeinfo))
1532

    
1533
    lu._VerifyFiles(nodeinfo, self.master_uuid, nvinfo,
1534
                    (files_all, files_opt, files_mc, files_vm))
1535

    
1536
    expected_msgs = [
1537
      "File %s found with 2 different checksums (variant 1 on"
1538
        " %s, %s, %s; variant 2 on %s)" %
1539
        (pathutils.RAPI_CERT_FILE, node1.name, node2.name, node3.name,
1540
         self.master.name),
1541
      "File %s is missing from node(s) %s" %
1542
        (pathutils.CLUSTER_DOMAIN_SECRET_FILE, node1.name),
1543
      "File %s should not exist on node(s) %s" %
1544
        (pathutils.CLUSTER_CONF_FILE, node3.name),
1545
      "File %s is missing from node(s) %s" %
1546
        (hv_xen.XEND_CONFIG_FILE, node3.name),
1547
      "File %s is missing from node(s) %s" %
1548
        (pathutils.CLUSTER_CONF_FILE, node2.name),
1549
      "File %s found with 2 different checksums (variant 1 on"
1550
        " %s; variant 2 on %s)" %
1551
        (pathutils.CLUSTER_CONF_FILE, self.master.name, node3.name),
1552
      "File %s is optional, but it must exist on all or no nodes (not"
1553
        " found on %s, %s, %s)" %
1554
        (pathutils.RAPI_USERS_FILE, self.master.name, node1.name, node2.name),
1555
      "File %s is optional, but it must exist on all or no nodes (not"
1556
        " found on %s)" % (hv_xen.XL_CONFIG_FILE, node1.name),
1557
      "Node did not return file checksum data",
1558
      ]
1559

    
1560
    self.assertEqual(len(self.mcpu.GetLogMessages()), len(expected_msgs))
1561
    for expected_msg in expected_msgs:
1562
      self.mcpu.assertLogContainsInLine(expected_msg)
1563

    
1564

    
1565
class TestLUClusterVerifyGroupVerifyNodeDrbd(TestLUClusterVerifyGroupMethods):
1566
  def setUp(self):
1567
    super(TestLUClusterVerifyGroupVerifyNodeDrbd, self).setUp()
1568

    
1569
    self.node1 = self.cfg.AddNewNode()
1570
    self.node2 = self.cfg.AddNewNode()
1571
    self.inst = self.cfg.AddNewInstance(
1572
      disks=[self.cfg.CreateDisk(dev_type=constants.LD_DRBD8,
1573
                                 primary_node=self.node1,
1574
                                 secondary_node=self.node2)],
1575
      admin_state=constants.ADMINST_UP)
1576

    
1577
  @withLockedLU
1578
  def testNoDrbdHelper(self, lu):
1579
    lu._VerifyNodeDrbd(self.master, {}, self.cfg.GetAllInstancesInfo(), None,
1580
                       self.cfg.ComputeDRBDMap())
1581
    self.mcpu.assertLogIsEmpty()
1582

    
1583
  @withLockedLU
1584
  def testDrbdHelperInvalidNodeResult(self, lu):
1585
    for ndata, expected in [({}, "no drbd usermode helper returned"),
1586
                            ({constants.NV_DRBDHELPER: (False, "")},
1587
                             "drbd usermode helper check unsuccessful"),
1588
                            ({constants.NV_DRBDHELPER: (True, "/bin/false")},
1589
                             "wrong drbd usermode helper")]:
1590
      self.mcpu.ClearLogMessages()
1591
      lu._VerifyNodeDrbd(self.master, ndata, self.cfg.GetAllInstancesInfo(),
1592
                         "/bin/true", self.cfg.ComputeDRBDMap())
1593
      self.mcpu.assertLogContainsRegex(expected)
1594

    
1595
  @withLockedLU
1596
  def testNoNodeResult(self, lu):
1597
    lu._VerifyNodeDrbd(self.node1, {}, self.cfg.GetAllInstancesInfo(),
1598
                         None, self.cfg.ComputeDRBDMap())
1599
    self.mcpu.assertLogContainsRegex("drbd minor 1 of .* is not active")
1600

    
1601
  @withLockedLU
1602
  def testInvalidNodeResult(self, lu):
1603
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: ""},
1604
                       self.cfg.GetAllInstancesInfo(), None,
1605
                       self.cfg.ComputeDRBDMap())
1606
    self.mcpu.assertLogContainsRegex("cannot parse drbd status file")
1607

    
1608
  @withLockedLU
1609
  def testWrongMinorInUse(self, lu):
1610
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: [2]},
1611
                       self.cfg.GetAllInstancesInfo(), None,
1612
                       self.cfg.ComputeDRBDMap())
1613
    self.mcpu.assertLogContainsRegex("drbd minor 1 of .* is not active")
1614
    self.mcpu.assertLogContainsRegex("unallocated drbd minor 2 is in use")
1615

    
1616
  @withLockedLU
1617
  def testValidResult(self, lu):
1618
    lu._VerifyNodeDrbd(self.node1, {constants.NV_DRBDLIST: [1]},
1619
                       self.cfg.GetAllInstancesInfo(), None,
1620
                       self.cfg.ComputeDRBDMap())
1621
    self.mcpu.assertLogIsEmpty()
1622

    
1623

    
1624
class TestLUClusterVerifyGroupVerifyNodeOs(TestLUClusterVerifyGroupMethods):
1625
  @withLockedLU
1626
  def testUpdateNodeOsInvalidNodeResult(self, lu):
1627
    for ndata in [{}, {constants.NV_OSLIST: ""}, {constants.NV_OSLIST: [""]},
1628
                  {constants.NV_OSLIST: [["1", "2"]]}]:
1629
      self.mcpu.ClearLogMessages()
1630
      nimage = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1631
      lu._UpdateNodeOS(self.master, ndata, nimage)
1632
      self.mcpu.assertLogContainsRegex("node hasn't returned valid OS data")
1633

    
1634
  @withLockedLU
1635
  def testUpdateNodeOsValidNodeResult(self, lu):
1636
    ndata = {
1637
      constants.NV_OSLIST: [
1638
        ["mock_OS", "/mocked/path", True, "", ["default"], [],
1639
         [constants.OS_API_V20]],
1640
        ["Another_Mock", "/random", True, "", ["var1", "var2"],
1641
         [{"param1": "val1"}, {"param2": "val2"}], constants.OS_API_VERSIONS]
1642
      ]
1643
    }
1644
    nimage = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1645
    lu._UpdateNodeOS(self.master, ndata, nimage)
1646
    self.mcpu.assertLogIsEmpty()
1647

    
1648
  @withLockedLU
1649
  def testVerifyNodeOs(self, lu):
1650
    node = self.cfg.AddNewNode()
1651
    nimg_root = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1652
    nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=node.uuid)
1653

    
1654
    nimg_root.os_fail = False
1655
    nimg_root.oslist = {
1656
      "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1657
                   set([constants.OS_API_V20]))],
1658
      "broken_base_os": [("/broken", False, "", set(), set(),
1659
                         set([constants.OS_API_V20]))],
1660
      "only_on_root": [("/random", True, "", set(), set(), set())],
1661
      "diffing_os": [("/pinky", True, "", set(["var1", "var2"]),
1662
                      set([("param1", "val1"), ("param2", "val2")]),
1663
                      set([constants.OS_API_V20]))]
1664
    }
1665
    nimg.os_fail = False
1666
    nimg.oslist = {
1667
      "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1668
                   set([constants.OS_API_V20]))],
1669
      "only_on_test": [("/random", True, "", set(), set(), set())],
1670
      "diffing_os": [("/bunny", True, "", set(["var1", "var3"]),
1671
                      set([("param1", "val1"), ("param3", "val3")]),
1672
                      set([constants.OS_API_V15]))],
1673
      "broken_os": [("/broken", False, "", set(), set(),
1674
                     set([constants.OS_API_V20]))],
1675
      "multi_entries": [
1676
        ("/multi1", True, "", set(), set(), set([constants.OS_API_V20])),
1677
        ("/multi2", True, "", set(), set(), set([constants.OS_API_V20]))]
1678
    }
1679

    
1680
    lu._VerifyNodeOS(node, nimg, nimg_root)
1681

    
1682
    expected_msgs = [
1683
      "Extra OS only_on_test not present on reference node",
1684
      "OSes present on reference node .* but missing on this node:" +
1685
        " only_on_root",
1686
      "OS API version for diffing_os differs",
1687
      "OS variants list for diffing_os differs",
1688
      "OS parameters for diffing_os differs",
1689
      "Invalid OS broken_os",
1690
      "Extra OS broken_os not present on reference node",
1691
      "OS 'multi_entries' has multiple entries",
1692
      "Extra OS multi_entries not present on reference node"
1693
    ]
1694

    
1695
    self.assertEqual(len(expected_msgs), len(self.mcpu.GetLogMessages()))
1696
    for expected_msg in expected_msgs:
1697
      self.mcpu.assertLogContainsRegex(expected_msg)
1698

    
1699

    
1700
class TestLUClusterVerifyGroupVerifyAcceptedFileStoragePaths(
1701
  TestLUClusterVerifyGroupMethods):
1702
  @withLockedLU
1703
  def testNotMaster(self, lu):
1704
    lu._VerifyAcceptedFileStoragePaths(self.master, {}, False)
1705
    self.mcpu.assertLogIsEmpty()
1706

    
1707
  @withLockedLU
1708
  def testNotMasterButRetunedValue(self, lu):
1709
    lu._VerifyAcceptedFileStoragePaths(
1710
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: []}, False)
1711
    self.mcpu.assertLogContainsRegex(
1712
      "Node should not have returned forbidden file storage paths")
1713

    
1714
  @withLockedLU
1715
  def testMasterInvalidNodeResult(self, lu):
1716
    lu._VerifyAcceptedFileStoragePaths(self.master, {}, True)
1717
    self.mcpu.assertLogContainsRegex(
1718
      "Node did not return forbidden file storage paths")
1719

    
1720
  @withLockedLU
1721
  def testMasterForbiddenPaths(self, lu):
1722
    lu._VerifyAcceptedFileStoragePaths(
1723
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: ["/forbidden"]}, True)
1724
    self.mcpu.assertLogContainsRegex("Found forbidden file storage paths")
1725

    
1726
  @withLockedLU
1727
  def testMasterSuccess(self, lu):
1728
    lu._VerifyAcceptedFileStoragePaths(
1729
      self.master, {constants.NV_ACCEPTED_STORAGE_PATHS: []}, True)
1730
    self.mcpu.assertLogIsEmpty()
1731

    
1732

    
1733
class TestLUClusterVerifyGroupVerifyStoragePaths(
1734
  TestLUClusterVerifyGroupMethods):
1735
  @withLockedLU
1736
  def testVerifyFileStoragePathsSuccess(self, lu):
1737
    lu._VerifyFileStoragePaths(self.master, {})
1738
    self.mcpu.assertLogIsEmpty()
1739

    
1740
  @withLockedLU
1741
  def testVerifyFileStoragePathsFailure(self, lu):
1742
    lu._VerifyFileStoragePaths(self.master,
1743
                               {constants.NV_FILE_STORAGE_PATH: "/fail/path"})
1744
    self.mcpu.assertLogContainsRegex(
1745
      "The configured file storage path is unusable")
1746

    
1747
  @withLockedLU
1748
  def testVerifySharedFileStoragePathsSuccess(self, lu):
1749
    lu._VerifySharedFileStoragePaths(self.master, {})
1750
    self.mcpu.assertLogIsEmpty()
1751

    
1752
  @withLockedLU
1753
  def testVerifySharedFileStoragePathsFailure(self, lu):
1754
    lu._VerifySharedFileStoragePaths(
1755
      self.master, {constants.NV_SHARED_FILE_STORAGE_PATH: "/fail/path"})
1756
    self.mcpu.assertLogContainsRegex(
1757
      "The configured sharedfile storage path is unusable")
1758

    
1759

    
1760
class TestLUClusterVerifyGroupVerifyOob(TestLUClusterVerifyGroupMethods):
1761
  @withLockedLU
1762
  def testEmptyResult(self, lu):
1763
    lu._VerifyOob(self.master, {})
1764
    self.mcpu.assertLogIsEmpty()
1765

    
1766
  @withLockedLU
1767
  def testErrorResults(self, lu):
1768
    lu._VerifyOob(self.master, {constants.NV_OOB_PATHS: ["path1", "path2"]})
1769
    self.mcpu.assertLogContainsRegex("path1")
1770
    self.mcpu.assertLogContainsRegex("path2")
1771

    
1772

    
1773
class TestLUClusterVerifyGroupUpdateNodeVolumes(
1774
  TestLUClusterVerifyGroupMethods):
1775
  def setUp(self):
1776
    super(TestLUClusterVerifyGroupUpdateNodeVolumes, self).setUp()
1777
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1778

    
1779
  @withLockedLU
1780
  def testNoVgName(self, lu):
1781
    lu._UpdateNodeVolumes(self.master, {}, self.nimg, None)
1782
    self.mcpu.assertLogIsEmpty()
1783
    self.assertTrue(self.nimg.lvm_fail)
1784

    
1785
  @withLockedLU
1786
  def testErrorMessage(self, lu):
1787
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: "mock error"},
1788
                          self.nimg, "mock_vg")
1789
    self.mcpu.assertLogContainsRegex("LVM problem on node: mock error")
1790
    self.assertTrue(self.nimg.lvm_fail)
1791

    
1792
  @withLockedLU
1793
  def testInvalidNodeResult(self, lu):
1794
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: [1, 2, 3]},
1795
                          self.nimg, "mock_vg")
1796
    self.mcpu.assertLogContainsRegex("rpc call to node failed")
1797
    self.assertTrue(self.nimg.lvm_fail)
1798

    
1799
  @withLockedLU
1800
  def testValidNodeResult(self, lu):
1801
    lu._UpdateNodeVolumes(self.master, {constants.NV_LVLIST: {}},
1802
                          self.nimg, "mock_vg")
1803
    self.mcpu.assertLogIsEmpty()
1804
    self.assertFalse(self.nimg.lvm_fail)
1805

    
1806

    
1807
class TestLUClusterVerifyGroupUpdateNodeInstances(
1808
  TestLUClusterVerifyGroupMethods):
1809
  def setUp(self):
1810
    super(TestLUClusterVerifyGroupUpdateNodeInstances, self).setUp()
1811
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1812

    
1813
  @withLockedLU
1814
  def testInvalidNodeResult(self, lu):
1815
    lu._UpdateNodeInstances(self.master, {}, self.nimg)
1816
    self.mcpu.assertLogContainsRegex("rpc call to node failed")
1817

    
1818
  @withLockedLU
1819
  def testValidNodeResult(self, lu):
1820
    inst = self.cfg.AddNewInstance()
1821
    lu._UpdateNodeInstances(self.master,
1822
                            {constants.NV_INSTANCELIST: [inst.name]},
1823
                            self.nimg)
1824
    self.mcpu.assertLogIsEmpty()
1825

    
1826

    
1827
class TestLUClusterVerifyGroupUpdateNodeInfo(TestLUClusterVerifyGroupMethods):
1828
  def setUp(self):
1829
    super(TestLUClusterVerifyGroupUpdateNodeInfo, self).setUp()
1830
    self.nimg = cluster.LUClusterVerifyGroup.NodeImage(uuid=self.master_uuid)
1831
    self.valid_hvresult = {constants.NV_HVINFO: {"memory_free": 1024}}
1832

    
1833
  @withLockedLU
1834
  def testInvalidHvNodeResult(self, lu):
1835
    for ndata in [{}, {constants.NV_HVINFO: ""}]:
1836
      self.mcpu.ClearLogMessages()
1837
      lu._UpdateNodeInfo(self.master, ndata, self.nimg, None)
1838
      self.mcpu.assertLogContainsRegex("rpc call to node failed")
1839

    
1840
  @withLockedLU
1841
  def testInvalidMemoryFreeHvNodeResult(self, lu):
1842
    lu._UpdateNodeInfo(self.master,
1843
                       {constants.NV_HVINFO: {"memory_free": "abc"}},
1844
                       self.nimg, None)
1845
    self.mcpu.assertLogContainsRegex(
1846
      "node returned invalid nodeinfo, check hypervisor")
1847

    
1848
  @withLockedLU
1849
  def testValidHvNodeResult(self, lu):
1850
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, None)
1851
    self.mcpu.assertLogIsEmpty()
1852

    
1853
  @withLockedLU
1854
  def testInvalidVgNodeResult(self, lu):
1855
    for vgdata in [[], ""]:
1856
      self.mcpu.ClearLogMessages()
1857
      ndata = {constants.NV_VGLIST: vgdata}
1858
      ndata.update(self.valid_hvresult)
1859
      lu._UpdateNodeInfo(self.master, ndata, self.nimg, "mock_vg")
1860
      self.mcpu.assertLogContainsRegex(
1861
        "node didn't return data for the volume group 'mock_vg'")
1862

    
1863
  @withLockedLU
1864
  def testInvalidDiskFreeVgNodeResult(self, lu):
1865
    self.valid_hvresult.update({
1866
      constants.NV_VGLIST: {"mock_vg": "abc"}
1867
    })
1868
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, "mock_vg")
1869
    self.mcpu.assertLogContainsRegex(
1870
      "node returned invalid LVM info, check LVM status")
1871

    
1872
  @withLockedLU
1873
  def testValidVgNodeResult(self, lu):
1874
    self.valid_hvresult.update({
1875
      constants.NV_VGLIST: {"mock_vg": 10000}
1876
    })
1877
    lu._UpdateNodeInfo(self.master, self.valid_hvresult, self.nimg, "mock_vg")
1878
    self.mcpu.assertLogIsEmpty()
1879

    
1880

    
1881
class TestLUClusterVerifyGroupCollectDiskInfo(TestLUClusterVerifyGroupMethods):
1882
  def setUp(self):
1883
    super(TestLUClusterVerifyGroupCollectDiskInfo, self).setUp()
1884

    
1885
    self.node1 = self.cfg.AddNewNode()
1886
    self.node2 = self.cfg.AddNewNode()
1887
    self.node3 = self.cfg.AddNewNode()
1888

    
1889
    self.diskless_inst = \
1890
      self.cfg.AddNewInstance(primary_node=self.node1,
1891
                              disk_template=constants.DT_DISKLESS)
1892
    self.plain_inst = \
1893
      self.cfg.AddNewInstance(primary_node=self.node2,
1894
                              disk_template=constants.DT_PLAIN)
1895
    self.drbd_inst = \
1896
      self.cfg.AddNewInstance(primary_node=self.node3,
1897
                              secondary_node=self.node2,
1898
                              disk_template=constants.DT_DRBD8)
1899

    
1900
    self.node1_img = cluster.LUClusterVerifyGroup.NodeImage(
1901
                       uuid=self.node1.uuid)
1902
    self.node1_img.pinst = [self.diskless_inst.uuid]
1903
    self.node1_img.sinst = []
1904
    self.node2_img = cluster.LUClusterVerifyGroup.NodeImage(
1905
                       uuid=self.node2.uuid)
1906
    self.node2_img.pinst = [self.plain_inst.uuid]
1907
    self.node2_img.sinst = [self.drbd_inst.uuid]
1908
    self.node3_img = cluster.LUClusterVerifyGroup.NodeImage(
1909
                       uuid=self.node3.uuid)
1910
    self.node3_img.pinst = [self.drbd_inst.uuid]
1911
    self.node3_img.sinst = []
1912

    
1913
    self.node_images = {
1914
      self.node1.uuid: self.node1_img,
1915
      self.node2.uuid: self.node2_img,
1916
      self.node3.uuid: self.node3_img
1917
    }
1918

    
1919
    self.node_uuids = [self.node1.uuid, self.node2.uuid, self.node3.uuid]
1920

    
1921
  @withLockedLU
1922
  def testSuccessfulRun(self, lu):
1923
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
1924
      RpcResultsBuilder() \
1925
        .AddSuccessfulNode(self.node2, [(True, ""), (True, "")]) \
1926
        .AddSuccessfulNode(self.node3, [(True, "")]) \
1927
        .Build()
1928

    
1929
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
1930
                        self.cfg.GetAllInstancesInfo())
1931

    
1932
    self.mcpu.assertLogIsEmpty()
1933

    
1934
  @withLockedLU
1935
  def testOfflineAndFailingNodes(self, lu):
1936
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
1937
      RpcResultsBuilder() \
1938
        .AddOfflineNode(self.node2) \
1939
        .AddFailedNode(self.node3) \
1940
        .Build()
1941

    
1942
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
1943
                        self.cfg.GetAllInstancesInfo())
1944

    
1945
    self.mcpu.assertLogContainsRegex("while getting disk information")
1946

    
1947
  @withLockedLU
1948
  def testInvalidNodeResult(self, lu):
1949
    self.rpc.call_blockdev_getmirrorstatus_multi.return_value = \
1950
      RpcResultsBuilder() \
1951
        .AddSuccessfulNode(self.node2, [(True,), (False,)]) \
1952
        .AddSuccessfulNode(self.node3, [""]) \
1953
        .Build()
1954

    
1955
    lu._CollectDiskInfo(self.node_uuids, self.node_images,
1956
                        self.cfg.GetAllInstancesInfo())
1957
    # logging is not performed through mcpu
1958
    self.mcpu.assertLogIsEmpty()
1959

    
1960

    
1961
class TestLUClusterVerifyGroupHooksCallBack(TestLUClusterVerifyGroupMethods):
1962
  def setUp(self):
1963
    super(TestLUClusterVerifyGroupHooksCallBack, self).setUp()
1964

    
1965
    self.feedback_fn = lambda _: None
1966

    
1967
  def PrepareLU(self, lu):
1968
    super(TestLUClusterVerifyGroupHooksCallBack, self).PrepareLU(lu)
1969

    
1970
    lu.my_node_uuids = list(self.cfg.GetAllNodesInfo().keys())
1971

    
1972
  @withLockedLU
1973
  def testEmptyGroup(self, lu):
1974
    lu.my_node_uuids = []
1975
    lu.HooksCallBack(constants.HOOKS_PHASE_POST, None, self.feedback_fn, None)
1976

    
1977
  @withLockedLU
1978
  def testFailedResult(self, lu):
1979
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
1980
                     RpcResultsBuilder(use_node_names=True)
1981
                       .AddFailedNode(self.master).Build(),
1982
                     self.feedback_fn,
1983
                     None)
1984
    self.mcpu.assertLogContainsRegex("Communication failure in hooks execution")
1985

    
1986
  @withLockedLU
1987
  def testOfflineNode(self, lu):
1988
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
1989
                     RpcResultsBuilder(use_node_names=True)
1990
                       .AddOfflineNode(self.master).Build(),
1991
                     self.feedback_fn,
1992
                     None)
1993

    
1994
  @withLockedLU
1995
  def testValidResult(self, lu):
1996
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
1997
                     RpcResultsBuilder(use_node_names=True)
1998
                       .AddSuccessfulNode(self.master,
1999
                                          [("mock_script",
2000
                                            constants.HKR_SUCCESS,
2001
                                            "mock output")])
2002
                       .Build(),
2003
                     self.feedback_fn,
2004
                     None)
2005

    
2006
  @withLockedLU
2007
  def testFailedScriptResult(self, lu):
2008
    lu.HooksCallBack(constants.HOOKS_PHASE_POST,
2009
                     RpcResultsBuilder(use_node_names=True)
2010
                       .AddSuccessfulNode(self.master,
2011
                                          [("mock_script",
2012
                                            constants.HKR_FAIL,
2013
                                            "mock output")])
2014
                       .Build(),
2015
                     self.feedback_fn,
2016
                     None)
2017
    self.mcpu.assertLogContainsRegex("Script mock_script failed")
2018

    
2019

    
2020
class TestLUClusterVerifyDisks(CmdlibTestCase):
2021
  def testVerifyDisks(self):
2022
    op = opcodes.OpClusterVerifyDisks()
2023
    result = self.ExecOpCode(op)
2024

    
2025
    self.assertEqual(1, len(result["jobs"]))
2026

    
2027

    
2028
if __name__ == "__main__":
2029
  testutils.GanetiTestProgram()