4 # Copyright (C) 2008, 2011, 2012, 2013 Google Inc.
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions are
11 # 1. Redistributions of source code must retain the above copyright notice,
12 # this list of conditions and the following disclaimer.
14 # 2. Redistributions in binary form must reproduce the above copyright
15 # notice, this list of conditions and the following disclaimer in the
16 # documentation and/or other materials provided with the distribution.
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
19 # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 """Tests for LUCluster*
44 from ganeti
.cmdlib
import cluster
45 from ganeti
import constants
46 from ganeti
import errors
47 from ganeti
import netutils
48 from ganeti
import objects
49 from ganeti
import opcodes
50 from ganeti
import utils
51 from ganeti
import pathutils
52 from ganeti
import query
53 from ganeti
.hypervisor
import hv_xen
55 from testsupport
import *
60 class TestClusterVerifySsh(unittest
.TestCase
):
61 def testMultipleGroups(self
):
62 fn
= cluster
.LUClusterVerifyGroup
._SelectSshCheckNodes
64 objects
.Node(name
="node20", group
="my", offline
=False),
65 objects
.Node(name
="node21", group
="my", offline
=False),
66 objects
.Node(name
="node22", group
="my", offline
=False),
67 objects
.Node(name
="node23", group
="my", offline
=False),
68 objects
.Node(name
="node24", group
="my", offline
=False),
69 objects
.Node(name
="node25", group
="my", offline
=False),
70 objects
.Node(name
="node26", group
="my", offline
=True),
73 objects
.Node(name
="node1", group
="g1", offline
=True),
74 objects
.Node(name
="node2", group
="g1", offline
=False),
75 objects
.Node(name
="node3", group
="g1", offline
=False),
76 objects
.Node(name
="node4", group
="g1", offline
=True),
77 objects
.Node(name
="node5", group
="g1", offline
=False),
78 objects
.Node(name
="node10", group
="xyz", offline
=False),
79 objects
.Node(name
="node11", group
="xyz", offline
=False),
80 objects
.Node(name
="node40", group
="alloff", offline
=True),
81 objects
.Node(name
="node41", group
="alloff", offline
=True),
82 objects
.Node(name
="node50", group
="aaa", offline
=False),
84 assert not utils
.FindDuplicates(map(operator
.attrgetter("name"), nodes
))
86 (online
, perhost
) = fn(mygroupnodes
, "my", nodes
)
87 self
.assertEqual(online
, ["node%s" % i
for i
in range(20, 26)])
88 self
.assertEqual(set(perhost
.keys()), set(online
))
90 self
.assertEqual(perhost
, {
91 "node20": ["node10", "node2", "node50"],
92 "node21": ["node11", "node3", "node50"],
93 "node22": ["node10", "node5", "node50"],
94 "node23": ["node11", "node2", "node50"],
95 "node24": ["node10", "node3", "node50"],
96 "node25": ["node11", "node5", "node50"],
99 def testSingleGroup(self
):
100 fn
= cluster
.LUClusterVerifyGroup
._SelectSshCheckNodes
102 objects
.Node(name
="node1", group
="default", offline
=True),
103 objects
.Node(name
="node2", group
="default", offline
=False),
104 objects
.Node(name
="node3", group
="default", offline
=False),
105 objects
.Node(name
="node4", group
="default", offline
=True),
107 assert not utils
.FindDuplicates(map(operator
.attrgetter("name"), nodes
))
109 (online
, perhost
) = fn(nodes
, "default", nodes
)
110 self
.assertEqual(online
, ["node2", "node3"])
111 self
.assertEqual(set(perhost
.keys()), set(online
))
113 self
.assertEqual(perhost
, {
119 class TestLUClusterActivateMasterIp(CmdlibTestCase
):
120 def testSuccess(self
):
121 op
= opcodes
.OpClusterActivateMasterIp()
123 self
.rpc
.call_node_activate_master_ip
.return_value
= \
124 self
.RpcResultsBuilder() \
125 .CreateSuccessfulNodeResult(self
.master
)
129 self
.rpc
.call_node_activate_master_ip
.assert_called_once_with(
130 self
.master_uuid
, self
.cfg
.GetMasterNetworkParameters(), False)
132 def testFailure(self
):
133 op
= opcodes
.OpClusterActivateMasterIp()
135 self
.rpc
.call_node_activate_master_ip
.return_value
= \
136 self
.RpcResultsBuilder() \
137 .CreateFailedNodeResult(self
.master
) \
139 self
.ExecOpCodeExpectOpExecError(op
)
142 class TestLUClusterDeactivateMasterIp(CmdlibTestCase
):
143 def testSuccess(self
):
144 op
= opcodes
.OpClusterDeactivateMasterIp()
146 self
.rpc
.call_node_deactivate_master_ip
.return_value
= \
147 self
.RpcResultsBuilder() \
148 .CreateSuccessfulNodeResult(self
.master
)
152 self
.rpc
.call_node_deactivate_master_ip
.assert_called_once_with(
153 self
.master_uuid
, self
.cfg
.GetMasterNetworkParameters(), False)
155 def testFailure(self
):
156 op
= opcodes
.OpClusterDeactivateMasterIp()
158 self
.rpc
.call_node_deactivate_master_ip
.return_value
= \
159 self
.RpcResultsBuilder() \
160 .CreateFailedNodeResult(self
.master
) \
162 self
.ExecOpCodeExpectOpExecError(op
)
165 class TestLUClusterConfigQuery(CmdlibTestCase
):
166 def testInvalidField(self
):
167 op
= opcodes
.OpClusterConfigQuery(output_fields
=["pinky_bunny"])
169 self
.ExecOpCodeExpectOpPrereqError(op
, "pinky_bunny")
171 def testAllFields(self
):
172 op
= opcodes
.OpClusterConfigQuery(output_fields
=query
.CLUSTER_FIELDS
.keys())
174 self
.rpc
.call_get_watcher_pause
.return_value
= \
175 self
.RpcResultsBuilder() \
176 .CreateSuccessfulNodeResult(self
.master
, -1)
178 ret
= self
.ExecOpCode(op
)
180 self
.assertEqual(1, self
.rpc
.call_get_watcher_pause
.call_count
)
181 self
.assertEqual(len(ret
), len(query
.CLUSTER_FIELDS
))
183 def testEmpytFields(self
):
184 op
= opcodes
.OpClusterConfigQuery(output_fields
=[])
188 self
.assertFalse(self
.rpc
.call_get_watcher_pause
.called
)
191 class TestLUClusterDestroy(CmdlibTestCase
):
192 def testExistingNodes(self
):
193 op
= opcodes
.OpClusterDestroy()
195 self
.cfg
.AddNewNode()
196 self
.cfg
.AddNewNode()
198 self
.ExecOpCodeExpectOpPrereqError(op
, "still 2 node\(s\)")
200 def testExistingInstances(self
):
201 op
= opcodes
.OpClusterDestroy()
203 self
.cfg
.AddNewInstance()
204 self
.cfg
.AddNewInstance()
206 self
.ExecOpCodeExpectOpPrereqError(op
, "still 2 instance\(s\)")
208 def testEmptyCluster(self
):
209 op
= opcodes
.OpClusterDestroy()
213 self
.assertSingleHooksCall([self
.master
.name
],
215 constants
.HOOKS_PHASE_POST
)
218 class TestLUClusterPostInit(CmdlibTestCase
):
220 def testExecution(self
):
221 op
= opcodes
.OpClusterPostInit()
225 self
.assertSingleHooksCall([self
.master
.uuid
],
227 constants
.HOOKS_PHASE_POST
)
230 class TestLUClusterQuery(CmdlibTestCase
):
231 def testSimpleInvocation(self
):
232 op
= opcodes
.OpClusterQuery()
236 def testIPv6Cluster(self
):
237 op
= opcodes
.OpClusterQuery()
239 self
.cluster
.primary_ip_family
= netutils
.IP6Address
.family
244 class TestLUClusterRedistConf(CmdlibTestCase
):
245 def testSimpleInvocation(self
):
246 op
= opcodes
.OpClusterRedistConf()
251 class TestLUClusterRename(CmdlibTestCase
):
252 NEW_NAME
= "new-name.example.com"
253 NEW_IP
= "203.0.113.100"
255 def testNoChanges(self
):
256 op
= opcodes
.OpClusterRename(name
=self
.cfg
.GetClusterName())
258 self
.ExecOpCodeExpectOpPrereqError(op
, "name nor the IP address")
260 def testReachableIp(self
):
261 op
= opcodes
.OpClusterRename(name
=self
.NEW_NAME
)
263 self
.netutils_mod
.GetHostname
.return_value
= \
264 HostnameMock(self
.NEW_NAME
, self
.NEW_IP
)
265 self
.netutils_mod
.TcpPing
.return_value
= True
267 self
.ExecOpCodeExpectOpPrereqError(op
, "is reachable on the network")
269 def testValidRename(self
):
270 op
= opcodes
.OpClusterRename(name
=self
.NEW_NAME
)
272 self
.netutils_mod
.GetHostname
.return_value
= \
273 HostnameMock(self
.NEW_NAME
, self
.NEW_IP
)
277 self
.assertEqual(1, self
.ssh_mod
.WriteKnownHostsFile
.call_count
)
278 self
.rpc
.call_node_deactivate_master_ip
.assert_called_once_with(
279 self
.master_uuid
, self
.cfg
.GetMasterNetworkParameters(), False)
280 self
.rpc
.call_node_activate_master_ip
.assert_called_once_with(
281 self
.master_uuid
, self
.cfg
.GetMasterNetworkParameters(), False)
283 def testRenameOfflineMaster(self
):
284 op
= opcodes
.OpClusterRename(name
=self
.NEW_NAME
)
286 self
.master
.offline
= True
287 self
.netutils_mod
.GetHostname
.return_value
= \
288 HostnameMock(self
.NEW_NAME
, self
.NEW_IP
)
293 class TestLUClusterRepairDiskSizes(CmdlibTestCase
):
294 def testNoInstances(self
):
295 op
= opcodes
.OpClusterRepairDiskSizes()
299 def _SetUpInstanceSingleDisk(self
, dev_type
=constants
.DT_PLAIN
):
301 snode
= self
.cfg
.AddNewNode()
303 disk
= self
.cfg
.CreateDisk(dev_type
=dev_type
,
305 secondary_node
=snode
)
306 inst
= self
.cfg
.AddNewInstance(disks
=[disk
])
310 def testSingleInstanceOnFailingNode(self
):
311 (inst
, _
) = self
._SetUpInstanceSingleDisk()
312 op
= opcodes
.OpClusterRepairDiskSizes(instances
=[inst
.name
])
314 self
.rpc
.call_blockdev_getdimensions
.return_value
= \
315 self
.RpcResultsBuilder() \
316 .CreateFailedNodeResult(self
.master
)
320 self
.mcpu
.assertLogContainsRegex("Failure in blockdev_getdimensions")
322 def _ExecOpClusterRepairDiskSizes(self
, node_data
):
323 # not specifying instances repairs all
324 op
= opcodes
.OpClusterRepairDiskSizes()
326 self
.rpc
.call_blockdev_getdimensions
.return_value
= \
327 self
.RpcResultsBuilder() \
328 .CreateSuccessfulNodeResult(self
.master
, node_data
)
330 return self
.ExecOpCode(op
)
332 def testInvalidResultData(self
):
333 for data
in [[], [None], ["invalid"], [("still", "invalid")]]:
336 self
._SetUpInstanceSingleDisk()
337 self
._ExecOpClusterRepairDiskSizes(data
)
339 self
.mcpu
.assertLogContainsRegex("ignoring")
341 def testCorrectSize(self
):
342 self
._SetUpInstanceSingleDisk()
343 changed
= self
._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
344 self
.mcpu
.assertLogIsEmpty()
345 self
.assertEqual(0, len(changed
))
347 def testWrongSize(self
):
348 self
._SetUpInstanceSingleDisk()
349 changed
= self
._ExecOpClusterRepairDiskSizes([(512 * 1024 * 1024, None)])
350 self
.assertEqual(1, len(changed
))
352 def testCorrectDRBD(self
):
353 self
._SetUpInstanceSingleDisk(dev_type
=constants
.DT_DRBD8
)
354 changed
= self
._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
355 self
.mcpu
.assertLogIsEmpty()
356 self
.assertEqual(0, len(changed
))
358 def testWrongDRBDChild(self
):
359 (_
, disk
) = self
._SetUpInstanceSingleDisk(dev_type
=constants
.DT_DRBD8
)
360 disk
.children
[0].size
= 512
361 changed
= self
._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
362 self
.assertEqual(1, len(changed
))
364 def testExclusiveStorageInvalidResultData(self
):
365 self
._SetUpInstanceSingleDisk()
366 self
.master
.ndparams
[constants
.ND_EXCLUSIVE_STORAGE
] = True
367 self
._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, None)])
369 self
.mcpu
.assertLogContainsRegex(
370 "did not return valid spindles information")
372 def testExclusiveStorageCorrectSpindles(self
):
373 (_
, disk
) = self
._SetUpInstanceSingleDisk()
375 self
.master
.ndparams
[constants
.ND_EXCLUSIVE_STORAGE
] = True
376 changed
= self
._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
377 self
.assertEqual(0, len(changed
))
379 def testExclusiveStorageWrongSpindles(self
):
380 self
._SetUpInstanceSingleDisk()
381 self
.master
.ndparams
[constants
.ND_EXCLUSIVE_STORAGE
] = True
382 changed
= self
._ExecOpClusterRepairDiskSizes([(1024 * 1024 * 1024, 1)])
383 self
.assertEqual(1, len(changed
))
386 class TestLUClusterSetParams(CmdlibTestCase
):
387 UID_POOL
= [(10, 1000)]
389 def testUidPool(self
):
390 op
= opcodes
.OpClusterSetParams(uid_pool
=self
.UID_POOL
)
392 self
.assertEqual(self
.UID_POOL
, self
.cluster
.uid_pool
)
394 def testAddUids(self
):
396 self
.cluster
.uid_pool
= list(old_pool
)
397 op
= opcodes
.OpClusterSetParams(add_uids
=self
.UID_POOL
)
399 self
.assertEqual(set(self
.UID_POOL
+ old_pool
),
400 set(self
.cluster
.uid_pool
))
402 def testRemoveUids(self
):
403 additional_pool
= [(1, 9)]
404 self
.cluster
.uid_pool
= self
.UID_POOL
+ additional_pool
405 op
= opcodes
.OpClusterSetParams(remove_uids
=self
.UID_POOL
)
407 self
.assertEqual(additional_pool
, self
.cluster
.uid_pool
)
409 def testMacPrefix(self
):
410 mac_prefix
= "aa:01:02"
411 op
= opcodes
.OpClusterSetParams(mac_prefix
=mac_prefix
)
413 self
.assertEqual(mac_prefix
, self
.cluster
.mac_prefix
)
415 def testEmptyMacPrefix(self
):
417 op
= opcodes
.OpClusterSetParams(mac_prefix
=mac_prefix
)
418 self
.ExecOpCodeExpectOpPrereqError(
419 op
, "Parameter 'OP_CLUSTER_SET_PARAMS.mac_prefix' fails validation")
421 def testInvalidMacPrefix(self
):
422 mac_prefix
= "az:00:00"
423 op
= opcodes
.OpClusterSetParams(mac_prefix
=mac_prefix
)
424 self
.ExecOpCodeExpectOpPrereqError(op
, "Invalid MAC address prefix")
426 def testMasterNetmask(self
):
427 op
= opcodes
.OpClusterSetParams(master_netmask
=26)
429 self
.assertEqual(26, self
.cluster
.master_netmask
)
431 def testInvalidDiskparams(self
):
432 for diskparams
in [{constants
.DT_DISKLESS
: {constants
.LV_STRIPES
: 0}},
433 {constants
.DT_DRBD8
: {constants
.RBD_POOL
: "pool"}},
434 {constants
.DT_DRBD8
: {constants
.RBD_ACCESS
: "bunny"}}]:
436 op
= opcodes
.OpClusterSetParams(diskparams
=diskparams
)
437 self
.ExecOpCodeExpectOpPrereqError(op
, "verify diskparams")
439 def testValidDiskparams(self
):
440 diskparams
= {constants
.DT_RBD
: {constants
.RBD_POOL
: "mock_pool",
441 constants
.RBD_ACCESS
: "kernelspace"}}
442 op
= opcodes
.OpClusterSetParams(diskparams
=diskparams
)
444 self
.assertEqual(diskparams
[constants
.DT_RBD
],
445 self
.cluster
.diskparams
[constants
.DT_RBD
])
447 def testMinimalDiskparams(self
):
448 diskparams
= {constants
.DT_RBD
: {constants
.RBD_POOL
: "mock_pool"}}
449 self
.cluster
.diskparams
= {}
450 op
= opcodes
.OpClusterSetParams(diskparams
=diskparams
)
452 self
.assertEqual(diskparams
, self
.cluster
.diskparams
)
454 def testValidDiskparamsAccess(self
):
455 for value
in constants
.DISK_VALID_ACCESS_MODES
:
457 op
= opcodes
.OpClusterSetParams(diskparams
={
458 constants
.DT_RBD
: {constants
.RBD_ACCESS
: value
}
461 got
= self
.cluster
.diskparams
[constants
.DT_RBD
][constants
.RBD_ACCESS
]
462 self
.assertEqual(value
, got
)
464 def testInvalidDiskparamsAccess(self
):
465 for value
in ["default", "pinky_bunny"]:
467 op
= opcodes
.OpClusterSetParams(diskparams
={
468 constants
.DT_RBD
: {constants
.RBD_ACCESS
: value
}
470 self
.ExecOpCodeExpectOpPrereqError(op
, "Invalid value of 'rbd:access'")
472 def testUnsetDrbdHelperWithDrbdDisks(self
):
473 self
.cfg
.AddNewInstance(disks
=[
474 self
.cfg
.CreateDisk(dev_type
=constants
.DT_DRBD8
, create_nodes
=True)])
475 op
= opcodes
.OpClusterSetParams(drbd_helper
="")
476 self
.ExecOpCodeExpectOpPrereqError(op
, "Cannot disable drbd helper")
478 def testFileStorageDir(self
):
479 op
= opcodes
.OpClusterSetParams(file_storage_dir
="/random/path")
481 self
.assertEqual("/random/path", self
.cluster
.file_storage_dir
)
483 def testSetFileStorageDirToCurrentValue(self
):
484 op
= opcodes
.OpClusterSetParams(
485 file_storage_dir
=self
.cluster
.file_storage_dir
)
488 self
.mcpu
.assertLogContainsRegex("file storage dir already set to value")
490 def testUnsetFileStorageDirFileStorageEnabled(self
):
491 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_FILE
])
492 op
= opcodes
.OpClusterSetParams(file_storage_dir
='')
493 self
.ExecOpCodeExpectOpPrereqError(op
, "Unsetting the 'file' storage")
495 def testUnsetFileStorageDirFileStorageDisabled(self
):
496 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_PLAIN
])
497 op
= opcodes
.OpClusterSetParams(file_storage_dir
='')
500 def testSetFileStorageDirFileStorageDisabled(self
):
501 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_PLAIN
])
502 op
= opcodes
.OpClusterSetParams(file_storage_dir
='/some/path/')
504 self
.mcpu
.assertLogContainsRegex("although file storage is not enabled")
506 def testSharedFileStorageDir(self
):
507 op
= opcodes
.OpClusterSetParams(shared_file_storage_dir
="/random/path")
509 self
.assertEqual("/random/path", self
.cluster
.shared_file_storage_dir
)
511 def testSetSharedFileStorageDirToCurrentValue(self
):
512 op
= opcodes
.OpClusterSetParams(shared_file_storage_dir
="/random/path")
514 op
= opcodes
.OpClusterSetParams(shared_file_storage_dir
="/random/path")
516 self
.mcpu
.assertLogContainsRegex("shared file storage dir already set to"
519 def testUnsetSharedFileStorageDirSharedFileStorageEnabled(self
):
520 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_SHARED_FILE
])
521 op
= opcodes
.OpClusterSetParams(shared_file_storage_dir
='')
522 self
.ExecOpCodeExpectOpPrereqError(op
, "Unsetting the 'sharedfile' storage")
524 def testUnsetSharedFileStorageDirSharedFileStorageDisabled(self
):
525 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_PLAIN
])
526 op
= opcodes
.OpClusterSetParams(shared_file_storage_dir
='')
529 def testSetSharedFileStorageDirSharedFileStorageDisabled(self
):
530 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_PLAIN
])
531 op
= opcodes
.OpClusterSetParams(shared_file_storage_dir
='/some/path/')
533 self
.mcpu
.assertLogContainsRegex("although sharedfile storage is not"
536 def testValidDrbdHelper(self
):
537 node1
= self
.cfg
.AddNewNode()
539 self
.rpc
.call_drbd_helper
.return_value
= \
540 self
.RpcResultsBuilder() \
541 .AddSuccessfulNode(self
.master
, "/bin/true") \
542 .AddOfflineNode(node1
) \
544 op
= opcodes
.OpClusterSetParams(drbd_helper
="/bin/true")
546 self
.mcpu
.assertLogContainsRegex("Not checking drbd helper on offline node")
548 def testDrbdHelperFailingNode(self
):
549 self
.rpc
.call_drbd_helper
.return_value
= \
550 self
.RpcResultsBuilder() \
551 .AddFailedNode(self
.master
) \
553 op
= opcodes
.OpClusterSetParams(drbd_helper
="/bin/true")
554 self
.ExecOpCodeExpectOpPrereqError(op
, "Error checking drbd helper")
556 def testInvalidDrbdHelper(self
):
557 self
.rpc
.call_drbd_helper
.return_value
= \
558 self
.RpcResultsBuilder() \
559 .AddSuccessfulNode(self
.master
, "/bin/false") \
561 op
= opcodes
.OpClusterSetParams(drbd_helper
="/bin/true")
562 self
.ExecOpCodeExpectOpPrereqError(op
, "drbd helper is /bin/false")
564 def testDrbdHelperWithoutDrbdDiskTemplate(self
):
565 drbd_helper
= "/bin/random_helper"
566 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DISKLESS
])
567 self
.rpc
.call_drbd_helper
.return_value
= \
568 self
.RpcResultsBuilder() \
569 .AddSuccessfulNode(self
.master
, drbd_helper
) \
571 op
= opcodes
.OpClusterSetParams(drbd_helper
=drbd_helper
)
574 self
.mcpu
.assertLogContainsRegex("but did not enable")
576 def testResetDrbdHelperDrbdDisabled(self
):
578 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DISKLESS
])
579 op
= opcodes
.OpClusterSetParams(drbd_helper
=drbd_helper
)
582 self
.assertEqual(None, self
.cluster
.drbd_usermode_helper
)
584 def testResetDrbdHelperDrbdEnabled(self
):
586 self
.cluster
.enabled_disk_templates
= [constants
.DT_DRBD8
]
587 op
= opcodes
.OpClusterSetParams(drbd_helper
=drbd_helper
)
588 self
.ExecOpCodeExpectOpPrereqError(
589 op
, "Cannot disable drbd helper while DRBD is enabled.")
591 def testEnableDrbdNoHelper(self
):
592 self
.cluster
.enabled_disk_templates
= [constants
.DT_DISKLESS
]
593 self
.cluster
.drbd_usermode_helper
= None
594 enabled_disk_templates
= [constants
.DT_DRBD8
]
595 op
= opcodes
.OpClusterSetParams(
596 enabled_disk_templates
=enabled_disk_templates
)
597 self
.ExecOpCodeExpectOpPrereqError(
598 op
, "Cannot enable DRBD without a DRBD usermode helper set")
600 def testEnableDrbdHelperSet(self
):
601 drbd_helper
= "/bin/random_helper"
602 self
.rpc
.call_drbd_helper
.return_value
= \
603 self
.RpcResultsBuilder() \
604 .AddSuccessfulNode(self
.master
, drbd_helper
) \
606 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DISKLESS
])
607 self
.cluster
.drbd_usermode_helper
= drbd_helper
608 enabled_disk_templates
= [constants
.DT_DRBD8
]
609 op
= opcodes
.OpClusterSetParams(
610 enabled_disk_templates
=enabled_disk_templates
,
611 ipolicy
={constants
.IPOLICY_DTS
: enabled_disk_templates
})
614 self
.assertEqual(drbd_helper
, self
.cluster
.drbd_usermode_helper
)
616 def testDrbdHelperAlreadySet(self
):
617 drbd_helper
= "/bin/true"
618 self
.rpc
.call_drbd_helper
.return_value
= \
619 self
.RpcResultsBuilder() \
620 .AddSuccessfulNode(self
.master
, "/bin/true") \
622 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DISKLESS
])
623 op
= opcodes
.OpClusterSetParams(drbd_helper
=drbd_helper
)
626 self
.assertEqual(drbd_helper
, self
.cluster
.drbd_usermode_helper
)
627 self
.mcpu
.assertLogContainsRegex("DRBD helper already in desired state")
629 def testSetDrbdHelper(self
):
630 drbd_helper
= "/bin/true"
631 self
.rpc
.call_drbd_helper
.return_value
= \
632 self
.RpcResultsBuilder() \
633 .AddSuccessfulNode(self
.master
, "/bin/true") \
635 self
.cluster
.drbd_usermode_helper
= "/bin/false"
636 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DRBD8
])
637 op
= opcodes
.OpClusterSetParams(drbd_helper
=drbd_helper
)
640 self
.assertEqual(drbd_helper
, self
.cluster
.drbd_usermode_helper
)
642 def testBeparams(self
):
643 beparams
= {constants
.BE_VCPUS
: 32}
644 op
= opcodes
.OpClusterSetParams(beparams
=beparams
)
646 self
.assertEqual(32, self
.cluster
647 .beparams
[constants
.PP_DEFAULT
][constants
.BE_VCPUS
])
649 def testNdparams(self
):
650 ndparams
= {constants
.ND_EXCLUSIVE_STORAGE
: True}
651 op
= opcodes
.OpClusterSetParams(ndparams
=ndparams
)
653 self
.assertEqual(True, self
.cluster
654 .ndparams
[constants
.ND_EXCLUSIVE_STORAGE
])
656 def testNdparamsResetOobProgram(self
):
657 ndparams
= {constants
.ND_OOB_PROGRAM
: ""}
658 op
= opcodes
.OpClusterSetParams(ndparams
=ndparams
)
660 self
.assertEqual(constants
.NDC_DEFAULTS
[constants
.ND_OOB_PROGRAM
],
661 self
.cluster
.ndparams
[constants
.ND_OOB_PROGRAM
])
663 def testHvState(self
):
664 hv_state
= {constants
.HT_FAKE
: {constants
.HVST_CPU_TOTAL
: 8}}
665 op
= opcodes
.OpClusterSetParams(hv_state
=hv_state
)
667 self
.assertEqual(8, self
.cluster
.hv_state_static
668 [constants
.HT_FAKE
][constants
.HVST_CPU_TOTAL
])
670 def testDiskState(self
):
672 constants
.DT_PLAIN
: {
673 "mock_vg": {constants
.DS_DISK_TOTAL
: 10}
676 op
= opcodes
.OpClusterSetParams(disk_state
=disk_state
)
678 self
.assertEqual(10, self
.cluster
679 .disk_state_static
[constants
.DT_PLAIN
]["mock_vg"]
680 [constants
.DS_DISK_TOTAL
])
682 def testDefaultIPolicy(self
):
683 ipolicy
= constants
.IPOLICY_DEFAULTS
684 op
= opcodes
.OpClusterSetParams(ipolicy
=ipolicy
)
687 def testIPolicyNewViolation(self
):
688 import ganeti
.constants
as C
689 ipolicy
= C
.IPOLICY_DEFAULTS
690 ipolicy
[C
.ISPECS_MINMAX
][0][C
.ISPECS_MIN
][C
.ISPEC_MEM_SIZE
] = 128
691 ipolicy
[C
.ISPECS_MINMAX
][0][C
.ISPECS_MAX
][C
.ISPEC_MEM_SIZE
] = 128
693 self
.cfg
.AddNewInstance(beparams
={C
.BE_MINMEM
: 512, C
.BE_MAXMEM
: 512})
694 op
= opcodes
.OpClusterSetParams(ipolicy
=ipolicy
)
697 self
.mcpu
.assertLogContainsRegex("instances violate them")
699 def testNicparamsNoInstance(self
):
701 constants
.NIC_LINK
: "mock_bridge"
703 op
= opcodes
.OpClusterSetParams(nicparams
=nicparams
)
706 self
.assertEqual("mock_bridge",
707 self
.cluster
.nicparams
708 [constants
.PP_DEFAULT
][constants
.NIC_LINK
])
710 def testNicparamsInvalidConf(self
):
712 constants
.NIC_MODE
: constants
.NIC_MODE_BRIDGED
,
713 constants
.NIC_LINK
: ""
715 op
= opcodes
.OpClusterSetParams(nicparams
=nicparams
)
716 self
.ExecOpCodeExpectException(op
, errors
.ConfigurationError
, "NIC link")
718 def testNicparamsInvalidInstanceConf(self
):
720 constants
.NIC_MODE
: constants
.NIC_MODE_BRIDGED
,
721 constants
.NIC_LINK
: "mock_bridge"
723 self
.cfg
.AddNewInstance(nics
=[
724 self
.cfg
.CreateNic(nicparams
={constants
.NIC_LINK
: None})])
725 op
= opcodes
.OpClusterSetParams(nicparams
=nicparams
)
726 self
.ExecOpCodeExpectOpPrereqError(op
, "Missing bridged NIC link")
728 def testNicparamsMissingIp(self
):
730 constants
.NIC_MODE
: constants
.NIC_MODE_ROUTED
732 self
.cfg
.AddNewInstance()
733 op
= opcodes
.OpClusterSetParams(nicparams
=nicparams
)
734 self
.ExecOpCodeExpectOpPrereqError(op
, "routed NIC with no ip address")
736 def testNicparamsWithInstance(self
):
738 constants
.NIC_LINK
: "mock_bridge"
740 self
.cfg
.AddNewInstance()
741 op
= opcodes
.OpClusterSetParams(nicparams
=nicparams
)
744 def testDefaultHvparams(self
):
745 hvparams
= constants
.HVC_DEFAULTS
746 op
= opcodes
.OpClusterSetParams(hvparams
=hvparams
)
749 self
.assertEqual(hvparams
, self
.cluster
.hvparams
)
751 def testMinimalHvparams(self
):
754 constants
.HV_MIGRATION_MODE
: constants
.HT_MIGRATION_NONLIVE
757 self
.cluster
.hvparams
= {}
758 op
= opcodes
.OpClusterSetParams(hvparams
=hvparams
)
761 self
.assertEqual(hvparams
, self
.cluster
.hvparams
)
767 constants
.HV_MIGRATION_MODE
: constants
.HT_MIGRATION_NONLIVE
770 "other_os": constants
.HVC_DEFAULTS
772 op
= opcodes
.OpClusterSetParams(os_hvp
=os_hvp
)
775 self
.assertEqual(constants
.HT_MIGRATION_NONLIVE
,
776 self
.cluster
.os_hvp
["mocked_os"][constants
.HT_FAKE
]
777 [constants
.HV_MIGRATION_MODE
])
778 self
.assertEqual(constants
.HVC_DEFAULTS
, self
.cluster
.os_hvp
["other_os"])
780 def testRemoveOsHvp(self
):
781 os_hvp
= {"mocked_os": {constants
.HT_FAKE
: None}}
782 op
= opcodes
.OpClusterSetParams(os_hvp
=os_hvp
)
785 assert constants
.HT_FAKE
not in self
.cluster
.os_hvp
["mocked_os"]
787 def testDefaultOsHvp(self
):
788 os_hvp
= {"mocked_os": constants
.HVC_DEFAULTS
.copy()}
789 self
.cluster
.os_hvp
= {"mocked_os": {}}
790 op
= opcodes
.OpClusterSetParams(os_hvp
=os_hvp
)
793 self
.assertEqual(os_hvp
, self
.cluster
.os_hvp
)
795 def testOsparams(self
):
805 self
.cluster
.osparams
= {"other_os": {"param1": "value1"}}
806 self
.cluster
.osparams_private_cluster
= {}
807 op
= opcodes
.OpClusterSetParams(osparams
=osparams
)
810 self
.assertEqual({"mocked_os": {"param1": "value1"}}, self
.cluster
.osparams
)
812 def testEnabledHypervisors(self
):
813 enabled_hypervisors
= [constants
.HT_XEN_HVM
, constants
.HT_XEN_PVM
]
814 op
= opcodes
.OpClusterSetParams(enabled_hypervisors
=enabled_hypervisors
)
817 self
.assertEqual(enabled_hypervisors
, self
.cluster
.enabled_hypervisors
)
819 def testEnabledHypervisorsWithoutHypervisorParams(self
):
820 enabled_hypervisors
= [constants
.HT_FAKE
]
821 self
.cluster
.hvparams
= {}
822 op
= opcodes
.OpClusterSetParams(enabled_hypervisors
=enabled_hypervisors
)
825 self
.assertEqual(enabled_hypervisors
, self
.cluster
.enabled_hypervisors
)
826 self
.assertEqual(constants
.HVC_DEFAULTS
[constants
.HT_FAKE
],
827 self
.cluster
.hvparams
[constants
.HT_FAKE
])
829 @testutils
.patch_object(utils
, "FindFile")
830 def testValidDefaultIallocator(self
, find_file_mock
):
831 find_file_mock
.return_value
= "/random/path"
832 default_iallocator
= "/random/path"
833 op
= opcodes
.OpClusterSetParams(default_iallocator
=default_iallocator
)
836 self
.assertEqual(default_iallocator
, self
.cluster
.default_iallocator
)
838 @testutils
.patch_object(utils
, "FindFile")
839 def testInvalidDefaultIallocator(self
, find_file_mock
):
840 find_file_mock
.return_value
= None
841 default_iallocator
= "/random/path"
842 op
= opcodes
.OpClusterSetParams(default_iallocator
=default_iallocator
)
843 self
.ExecOpCodeExpectOpPrereqError(op
, "Invalid default iallocator script")
845 def testEnabledDiskTemplates(self
):
846 enabled_disk_templates
= [constants
.DT_DISKLESS
, constants
.DT_PLAIN
]
847 op
= opcodes
.OpClusterSetParams(
848 enabled_disk_templates
=enabled_disk_templates
,
849 ipolicy
={constants
.IPOLICY_DTS
: enabled_disk_templates
})
852 self
.assertEqual(enabled_disk_templates
,
853 self
.cluster
.enabled_disk_templates
)
855 def testEnabledDiskTemplatesVsIpolicy(self
):
856 enabled_disk_templates
= [constants
.DT_DISKLESS
, constants
.DT_PLAIN
]
857 op
= opcodes
.OpClusterSetParams(
858 enabled_disk_templates
=enabled_disk_templates
,
859 ipolicy
={constants
.IPOLICY_DTS
: [constants
.DT_FILE
]})
860 self
.ExecOpCodeExpectOpPrereqError(op
, "but not enabled on the cluster")
862 def testDisablingDiskTemplatesOfInstances(self
):
863 old_disk_templates
= [constants
.DT_DISKLESS
, constants
.DT_PLAIN
]
864 self
.cfg
.SetEnabledDiskTemplates(old_disk_templates
)
865 self
.cfg
.AddNewInstance(
866 disks
=[self
.cfg
.CreateDisk(dev_type
=constants
.DT_PLAIN
)])
867 new_disk_templates
= [constants
.DT_DISKLESS
, constants
.DT_DRBD8
]
868 op
= opcodes
.OpClusterSetParams(
869 enabled_disk_templates
=new_disk_templates
,
870 ipolicy
={constants
.IPOLICY_DTS
: new_disk_templates
})
871 self
.ExecOpCodeExpectOpPrereqError(op
, "least one instance using it")
873 def testEnabledDiskTemplatesWithoutVgName(self
):
874 enabled_disk_templates
= [constants
.DT_PLAIN
]
875 self
.cluster
.volume_group_name
= None
876 op
= opcodes
.OpClusterSetParams(
877 enabled_disk_templates
=enabled_disk_templates
)
878 self
.ExecOpCodeExpectOpPrereqError(op
, "specify a volume group")
880 def testDisableDiskTemplateWithExistingInstance(self
):
881 enabled_disk_templates
= [constants
.DT_DISKLESS
]
882 self
.cfg
.AddNewInstance(
883 disks
=[self
.cfg
.CreateDisk(dev_type
=constants
.DT_PLAIN
)])
884 op
= opcodes
.OpClusterSetParams(
885 enabled_disk_templates
=enabled_disk_templates
,
886 ipolicy
={constants
.IPOLICY_DTS
: enabled_disk_templates
})
887 self
.ExecOpCodeExpectOpPrereqError(op
, "Cannot disable disk template")
889 def testVgNameNoLvmDiskTemplateEnabled(self
):
891 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DISKLESS
])
892 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
895 self
.assertEqual(vg_name
, self
.cluster
.volume_group_name
)
896 self
.mcpu
.assertLogIsEmpty()
898 def testUnsetVgNameWithLvmDiskTemplateEnabled(self
):
900 self
.cluster
.enabled_disk_templates
= [constants
.DT_PLAIN
]
901 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
902 self
.ExecOpCodeExpectOpPrereqError(op
, "Cannot unset volume group")
904 def testUnsetVgNameWithLvmInstance(self
):
906 self
.cfg
.AddNewInstance(
907 disks
=[self
.cfg
.CreateDisk(dev_type
=constants
.DT_PLAIN
)])
908 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
909 self
.ExecOpCodeExpectOpPrereqError(op
, "Cannot unset volume group")
911 def testUnsetVgNameWithNoLvmDiskTemplateEnabled(self
):
913 self
.cfg
.SetEnabledDiskTemplates([constants
.DT_DISKLESS
])
914 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
917 self
.assertEqual(None, self
.cluster
.volume_group_name
)
919 def testVgNameToOldName(self
):
920 vg_name
= self
.cluster
.volume_group_name
921 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
924 self
.mcpu
.assertLogContainsRegex("already in desired state")
926 def testVgNameWithFailingNode(self
):
928 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
929 self
.rpc
.call_vg_list
.return_value
= \
930 self
.RpcResultsBuilder() \
931 .AddFailedNode(self
.master
) \
935 self
.mcpu
.assertLogContainsRegex("Error while gathering data on node")
937 def testVgNameWithValidNode(self
):
939 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
940 self
.rpc
.call_vg_list
.return_value
= \
941 self
.RpcResultsBuilder() \
942 .AddSuccessfulNode(self
.master
, {vg_name
: 1024 * 1024}) \
946 def testVgNameWithTooSmallNode(self
):
948 op
= opcodes
.OpClusterSetParams(vg_name
=vg_name
)
949 self
.rpc
.call_vg_list
.return_value
= \
950 self
.RpcResultsBuilder() \
951 .AddSuccessfulNode(self
.master
, {vg_name
: 1}) \
953 self
.ExecOpCodeExpectOpPrereqError(op
, "too small")
955 def testMiscParameters(self
):
956 op
= opcodes
.OpClusterSetParams(candidate_pool_size
=123,
957 maintain_node_health
=True,
958 modify_etc_hosts
=True,
959 prealloc_wipe_disks
=True,
960 reserved_lvs
=["/dev/mock_lv"],
961 use_external_mip_script
=True)
964 self
.mcpu
.assertLogIsEmpty()
965 self
.assertEqual(123, self
.cluster
.candidate_pool_size
)
966 self
.assertEqual(True, self
.cluster
.maintain_node_health
)
967 self
.assertEqual(True, self
.cluster
.modify_etc_hosts
)
968 self
.assertEqual(True, self
.cluster
.prealloc_wipe_disks
)
969 self
.assertEqual(["/dev/mock_lv"], self
.cluster
.reserved_lvs
)
970 self
.assertEqual(True, self
.cluster
.use_external_mip_script
)
972 def testAddHiddenOs(self
):
973 self
.cluster
.hidden_os
= ["hidden1", "hidden2"]
974 op
= opcodes
.OpClusterSetParams(hidden_os
=[(constants
.DDM_ADD
, "hidden2"),
975 (constants
.DDM_ADD
, "hidden3")])
978 self
.assertEqual(["hidden1", "hidden2", "hidden3"], self
.cluster
.hidden_os
)
979 self
.mcpu
.assertLogContainsRegex("OS hidden2 already")
981 def testRemoveBlacklistedOs(self
):
982 self
.cluster
.blacklisted_os
= ["blisted1", "blisted2"]
983 op
= opcodes
.OpClusterSetParams(blacklisted_os
=[
984 (constants
.DDM_REMOVE
, "blisted2"),
985 (constants
.DDM_REMOVE
, "blisted3")])
988 self
.assertEqual(["blisted1"], self
.cluster
.blacklisted_os
)
989 self
.mcpu
.assertLogContainsRegex("OS blisted3 not found")
991 def testMasterNetdev(self
):
992 master_netdev
= "test_dev"
993 op
= opcodes
.OpClusterSetParams(master_netdev
=master_netdev
)
996 self
.assertEqual(master_netdev
, self
.cluster
.master_netdev
)
998 def testMasterNetdevFailNoForce(self
):
999 master_netdev
= "test_dev"
1000 op
= opcodes
.OpClusterSetParams(master_netdev
=master_netdev
)
1001 self
.rpc
.call_node_deactivate_master_ip
.return_value
= \
1002 self
.RpcResultsBuilder() \
1003 .CreateFailedNodeResult(self
.master
)
1004 self
.ExecOpCodeExpectOpExecError(op
, "Could not disable the master ip")
1006 def testMasterNetdevFailForce(self
):
1007 master_netdev
= "test_dev"
1008 op
= opcodes
.OpClusterSetParams(master_netdev
=master_netdev
,
1010 self
.rpc
.call_node_deactivate_master_ip
.return_value
= \
1011 self
.RpcResultsBuilder() \
1012 .CreateFailedNodeResult(self
.master
)
1015 self
.mcpu
.assertLogContainsRegex("Could not disable the master ip")
1017 def testCompressionToolSuccess(self
):
1018 compression_tools
= ["certainly_not_a_default", "gzip"]
1019 op
= opcodes
.OpClusterSetParams(compression_tools
=compression_tools
)
1021 self
.assertEqual(compression_tools
, self
.cluster
.compression_tools
)
1023 def testCompressionToolCompatibility(self
):
1024 compression_tools
= ["not_gzip", "not_not_not_gzip"]
1025 op
= opcodes
.OpClusterSetParams(compression_tools
=compression_tools
)
1026 self
.ExecOpCodeExpectOpPrereqError(op
, ".*the gzip utility must be.*")
1028 def testCompressionToolForbiddenValues(self
):
1029 for value
in ["none", "\"rm -rf all.all\"", "ls$IFS-la"]:
1030 compression_tools
= [value
, "gzip"]
1031 op
= opcodes
.OpClusterSetParams(compression_tools
=compression_tools
)
1032 self
.ExecOpCodeExpectOpPrereqError(op
, re
.escape(value
))
1035 class TestLUClusterVerify(CmdlibTestCase
):
1036 def testVerifyAllGroups(self
):
1037 op
= opcodes
.OpClusterVerify()
1038 result
= self
.ExecOpCode(op
)
1040 self
.assertEqual(2, len(result
["jobs"]))
1042 def testVerifyDefaultGroups(self
):
1043 op
= opcodes
.OpClusterVerify(group_name
="default")
1044 result
= self
.ExecOpCode(op
)
1046 self
.assertEqual(1, len(result
["jobs"]))
1049 class TestLUClusterVerifyConfig(CmdlibTestCase
):
1052 super(TestLUClusterVerifyConfig
, self
).setUp()
1054 self
._load_cert_patcher
= testutils \
1055 .patch_object(OpenSSL
.crypto
, "load_certificate")
1056 self
._load_cert_mock
= self
._load_cert_patcher
.start()
1057 self
._verify_cert_patcher
= testutils \
1058 .patch_object(utils
, "VerifyCertificate")
1059 self
._verify_cert_mock
= self
._verify_cert_patcher
.start()
1060 self
._read_file_patcher
= testutils
.patch_object(utils
, "ReadFile")
1061 self
._read_file_mock
= self
._read_file_patcher
.start()
1062 self
._can_read_patcher
= testutils
.patch_object(utils
, "CanRead")
1063 self
._can_read_mock
= self
._can_read_patcher
.start()
1065 self
._can_read_mock
.return_value
= True
1066 self
._read_file_mock
.return_value
= True
1067 self
._verify_cert_mock
.return_value
= (None, "")
1068 self
._load_cert_mock
.return_value
= True
1071 super(TestLUClusterVerifyConfig
, self
).tearDown()
1073 self
._can_read_patcher
.stop()
1074 self
._read_file_patcher
.stop()
1075 self
._verify_cert_patcher
.stop()
1076 self
._load_cert_patcher
.stop()
1078 def testSuccessfulRun(self
):
1079 self
.cfg
.AddNewInstance()
1080 op
= opcodes
.OpClusterVerifyConfig()
1081 result
= self
.ExecOpCode(op
)
1082 self
.assertTrue(result
)
1084 def testDanglingNode(self
):
1085 node
= self
.cfg
.AddNewNode()
1086 self
.cfg
.AddNewInstance(primary_node
=node
)
1087 node
.group
= "invalid"
1088 op
= opcodes
.OpClusterVerifyConfig()
1089 result
= self
.ExecOpCode(op
)
1091 self
.mcpu
.assertLogContainsRegex(
1092 "following nodes \(and their instances\) belong to a non existing group")
1093 self
.assertFalse(result
)
1095 def testDanglingInstance(self
):
1096 inst
= self
.cfg
.AddNewInstance()
1097 inst
.primary_node
= "invalid"
1098 op
= opcodes
.OpClusterVerifyConfig()
1099 result
= self
.ExecOpCode(op
)
1101 self
.mcpu
.assertLogContainsRegex(
1102 "following instances have a non-existing primary-node")
1103 self
.assertFalse(result
)
1106 class TestLUClusterVerifyGroup(CmdlibTestCase
):
1107 def testEmptyNodeGroup(self
):
1108 group
= self
.cfg
.AddNewNodeGroup()
1109 op
= opcodes
.OpClusterVerifyGroup(group_name
=group
.name
, verbose
=True)
1111 result
= self
.ExecOpCode(op
)
1113 self
.assertTrue(result
)
1114 self
.mcpu
.assertLogContainsRegex("Empty node group, skipping verification")
1116 def testSimpleInvocation(self
):
1117 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1121 def testSimpleInvocationWithInstance(self
):
1122 self
.cfg
.AddNewInstance(disks
=[])
1123 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1127 def testGhostNode(self
):
1128 group
= self
.cfg
.AddNewNodeGroup()
1129 node
= self
.cfg
.AddNewNode(group
=group
.uuid
, offline
=True)
1130 self
.master
.offline
= True
1131 self
.cfg
.AddNewInstance(disk_template
=constants
.DT_DRBD8
,
1132 primary_node
=self
.master
,
1133 secondary_node
=node
)
1135 self
.rpc
.call_blockdev_getmirrorstatus_multi
.return_value
= \
1136 RpcResultsBuilder() \
1137 .AddOfflineNode(self
.master
) \
1140 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1144 def testValidRpcResult(self
):
1145 self
.cfg
.AddNewInstance(disks
=[])
1147 self
.rpc
.call_node_verify
.return_value
= \
1148 RpcResultsBuilder() \
1149 .AddSuccessfulNode(self
.master
, {}) \
1152 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1157 class TestLUClusterVerifyClientCerts(CmdlibTestCase
):
1159 def _AddNormalNode(self
):
1160 self
.normalnode
= copy
.deepcopy(self
.master
)
1161 self
.normalnode
.master_candidate
= False
1162 self
.normalnode
.uuid
= "normal-node-uuid"
1163 self
.cfg
.AddNode(self
.normalnode
, None)
1165 def testVerifyMasterCandidate(self
):
1166 client_cert
= "client-cert-digest"
1167 self
.cluster
.candidate_certs
= {self
.master
.uuid
: client_cert
}
1168 self
.rpc
.call_node_verify
.return_value
= \
1169 RpcResultsBuilder() \
1170 .AddSuccessfulNode(self
.master
,
1171 {constants
.NV_CLIENT_CERT
: (None, client_cert
)}) \
1173 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1176 def testVerifyMasterCandidateInvalid(self
):
1177 client_cert
= "client-cert-digest"
1178 self
.cluster
.candidate_certs
= {self
.master
.uuid
: client_cert
}
1179 self
.rpc
.call_node_verify
.return_value
= \
1180 RpcResultsBuilder() \
1181 .AddSuccessfulNode(self
.master
,
1182 {constants
.NV_CLIENT_CERT
: (666, "Invalid Certificate")}) \
1184 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1186 self
.mcpu
.assertLogContainsRegex("Client certificate")
1187 self
.mcpu
.assertLogContainsRegex("failed validation")
1189 def testVerifyNoMasterCandidateMap(self
):
1190 client_cert
= "client-cert-digest"
1191 self
.cluster
.candidate_certs
= {}
1192 self
.rpc
.call_node_verify
.return_value
= \
1193 RpcResultsBuilder() \
1194 .AddSuccessfulNode(self
.master
,
1195 {constants
.NV_CLIENT_CERT
: (None, client_cert
)}) \
1197 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1199 self
.mcpu
.assertLogContainsRegex(
1200 "list of master candidate certificates is empty")
1202 def testVerifyNoSharingMasterCandidates(self
):
1203 client_cert
= "client-cert-digest"
1204 self
.cluster
.candidate_certs
= {
1205 self
.master
.uuid
: client_cert
,
1206 "some-other-master-candidate-uuid": client_cert
}
1207 self
.rpc
.call_node_verify
.return_value
= \
1208 RpcResultsBuilder() \
1209 .AddSuccessfulNode(self
.master
,
1210 {constants
.NV_CLIENT_CERT
: (None, client_cert
)}) \
1212 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1214 self
.mcpu
.assertLogContainsRegex(
1215 "two master candidates configured to use the same")
1217 def testVerifyMasterCandidateCertMismatch(self
):
1218 client_cert
= "client-cert-digest"
1219 self
.cluster
.candidate_certs
= {self
.master
.uuid
: "different-cert-digest"}
1220 self
.rpc
.call_node_verify
.return_value
= \
1221 RpcResultsBuilder() \
1222 .AddSuccessfulNode(self
.master
,
1223 {constants
.NV_CLIENT_CERT
: (None, client_cert
)}) \
1225 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1227 self
.mcpu
.assertLogContainsRegex("does not match its entry")
1229 def testVerifyMasterCandidateUnregistered(self
):
1230 client_cert
= "client-cert-digest"
1231 self
.cluster
.candidate_certs
= {"other-node-uuid": "different-cert-digest"}
1232 self
.rpc
.call_node_verify
.return_value
= \
1233 RpcResultsBuilder() \
1234 .AddSuccessfulNode(self
.master
,
1235 {constants
.NV_CLIENT_CERT
: (None, client_cert
)}) \
1237 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1239 self
.mcpu
.assertLogContainsRegex("does not have an entry")
1241 def testVerifyMasterCandidateOtherNodesCert(self
):
1242 client_cert
= "client-cert-digest"
1243 self
.cluster
.candidate_certs
= {"other-node-uuid": client_cert
}
1244 self
.rpc
.call_node_verify
.return_value
= \
1245 RpcResultsBuilder() \
1246 .AddSuccessfulNode(self
.master
,
1247 {constants
.NV_CLIENT_CERT
: (None, client_cert
)}) \
1249 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1251 self
.mcpu
.assertLogContainsRegex("using a certificate of another node")
1253 def testNormalNodeStillInList(self
):
1254 self
._AddNormalNode()
1255 client_cert_master
= "client-cert-digest-master"
1256 client_cert_normal
= "client-cert-digest-normal"
1257 self
.cluster
.candidate_certs
= {
1258 self
.normalnode
.uuid
: client_cert_normal
,
1259 self
.master
.uuid
: client_cert_master
}
1260 self
.rpc
.call_node_verify
.return_value
= \
1261 RpcResultsBuilder() \
1262 .AddSuccessfulNode(self
.normalnode
,
1263 {constants
.NV_CLIENT_CERT
: (None, client_cert_normal
)}) \
1264 .AddSuccessfulNode(self
.master
,
1265 {constants
.NV_CLIENT_CERT
: (None, client_cert_master
)}) \
1267 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1269 self
.mcpu
.assertLogContainsRegex("not a master candidate")
1270 self
.mcpu
.assertLogContainsRegex("still listed")
1272 def testNormalNodeStealingMasterCandidateCert(self
):
1273 self
._AddNormalNode()
1274 client_cert_master
= "client-cert-digest-master"
1275 self
.cluster
.candidate_certs
= {
1276 self
.master
.uuid
: client_cert_master
}
1277 self
.rpc
.call_node_verify
.return_value
= \
1278 RpcResultsBuilder() \
1279 .AddSuccessfulNode(self
.normalnode
,
1280 {constants
.NV_CLIENT_CERT
: (None, client_cert_master
)}) \
1281 .AddSuccessfulNode(self
.master
,
1282 {constants
.NV_CLIENT_CERT
: (None, client_cert_master
)}) \
1284 op
= opcodes
.OpClusterVerifyGroup(group_name
="default", verbose
=True)
1286 self
.mcpu
.assertLogContainsRegex("not a master candidate")
1287 self
.mcpu
.assertLogContainsRegex(
1288 "certificate of another node which is master candidate")
1291 class TestLUClusterVerifyGroupMethods(CmdlibTestCase
):
1292 """Base class for testing individual methods in LUClusterVerifyGroup.
1296 super(TestLUClusterVerifyGroupMethods
, self
).setUp()
1297 self
.op
= opcodes
.OpClusterVerifyGroup(group_name
="default")
1299 def PrepareLU(self
, lu
):
1300 lu
._exclusive_storage
= False
1301 lu
.master_node
= self
.master_uuid
1302 lu
.group_info
= self
.group
1303 cluster
.LUClusterVerifyGroup
.all_node_info
= \
1304 property(fget
=lambda _
: self
.cfg
.GetAllNodesInfo())
1307 class TestLUClusterVerifyGroupVerifyNode(TestLUClusterVerifyGroupMethods
):
1309 def testInvalidNodeResult(self
, lu
):
1310 self
.assertFalse(lu
._VerifyNode(self
.master
, None))
1311 self
.assertFalse(lu
._VerifyNode(self
.master
, ""))
1314 def testInvalidVersion(self
, lu
):
1315 self
.assertFalse(lu
._VerifyNode(self
.master
, {"version": None}))
1316 self
.assertFalse(lu
._VerifyNode(self
.master
, {"version": ""}))
1317 self
.assertFalse(lu
._VerifyNode(self
.master
, {
1318 "version": (constants
.PROTOCOL_VERSION
- 1, constants
.RELEASE_VERSION
)
1321 self
.mcpu
.ClearLogMessages()
1322 self
.assertTrue(lu
._VerifyNode(self
.master
, {
1323 "version": (constants
.PROTOCOL_VERSION
, constants
.RELEASE_VERSION
+ "x")
1325 self
.mcpu
.assertLogContainsRegex("software version mismatch")
1327 def _GetValidNodeResult(self
, additional_fields
):
1329 "version": (constants
.PROTOCOL_VERSION
, constants
.RELEASE_VERSION
),
1330 constants
.NV_NODESETUP
: []
1332 ret
.update(additional_fields
)
1336 def testHypervisor(self
, lu
):
1337 lu
._VerifyNode(self
.master
, self
._GetValidNodeResult({
1338 constants
.NV_HYPERVISOR
: {
1339 constants
.HT_XEN_PVM
: None,
1340 constants
.HT_XEN_HVM
: "mock error"
1343 self
.mcpu
.assertLogContainsRegex(constants
.HT_XEN_HVM
)
1344 self
.mcpu
.assertLogContainsRegex("mock error")
1347 def testHvParams(self
, lu
):
1348 lu
._VerifyNode(self
.master
, self
._GetValidNodeResult({
1349 constants
.NV_HVPARAMS
: [("mock item", constants
.HT_XEN_HVM
, "mock error")]
1351 self
.mcpu
.assertLogContainsRegex(constants
.HT_XEN_HVM
)
1352 self
.mcpu
.assertLogContainsRegex("mock item")
1353 self
.mcpu
.assertLogContainsRegex("mock error")
1356 def testSuccessfulResult(self
, lu
):
1357 self
.assertTrue(lu
._VerifyNode(self
.master
, self
._GetValidNodeResult({})))
1358 self
.mcpu
.assertLogIsEmpty()
1361 class TestLUClusterVerifyGroupVerifyNodeTime(TestLUClusterVerifyGroupMethods
):
1363 def testInvalidNodeResult(self
, lu
):
1364 for ndata
in [{}, {constants
.NV_TIME
: "invalid"}]:
1365 self
.mcpu
.ClearLogMessages()
1366 lu
._VerifyNodeTime(self
.master
, ndata
, None, None)
1368 self
.mcpu
.assertLogContainsRegex("Node returned invalid time")
1371 def testNodeDiverges(self
, lu
):
1372 for ntime
in [(0, 0), (2000, 0)]:
1373 self
.mcpu
.ClearLogMessages()
1374 lu
._VerifyNodeTime(self
.master
, {constants
.NV_TIME
: ntime
}, 1000, 1005)
1376 self
.mcpu
.assertLogContainsRegex("Node time diverges")
1379 def testSuccessfulResult(self
, lu
):
1380 lu
._VerifyNodeTime(self
.master
, {constants
.NV_TIME
: (0, 0)}, 0, 5)
1381 self
.mcpu
.assertLogIsEmpty()
1384 class TestLUClusterVerifyGroupUpdateVerifyNodeLVM(
1385 TestLUClusterVerifyGroupMethods
):
1387 super(TestLUClusterVerifyGroupUpdateVerifyNodeLVM
, self
).setUp()
1388 self
.VALID_NRESULT
= {
1389 constants
.NV_VGLIST
: {"mock_vg": 30000},
1390 constants
.NV_PVLIST
: [
1393 "vg_name": "mock_vg",
1403 def testNoVgName(self
, lu
):
1404 lu
._UpdateVerifyNodeLVM(self
.master
, {}, None, None)
1405 self
.mcpu
.assertLogIsEmpty()
1408 def testEmptyNodeResult(self
, lu
):
1409 lu
._UpdateVerifyNodeLVM(self
.master
, {}, "mock_vg", None)
1410 self
.mcpu
.assertLogContainsRegex("unable to check volume groups")
1411 self
.mcpu
.assertLogContainsRegex("Can't get PV list from node")
1414 def testValidNodeResult(self
, lu
):
1415 lu
._UpdateVerifyNodeLVM(self
.master
, self
.VALID_NRESULT
, "mock_vg", None)
1416 self
.mcpu
.assertLogIsEmpty()
1419 def testValidNodeResultExclusiveStorage(self
, lu
):
1420 lu
._exclusive_storage
= True
1421 lu
._UpdateVerifyNodeLVM(self
.master
, self
.VALID_NRESULT
, "mock_vg",
1422 cluster
.LUClusterVerifyGroup
.NodeImage())
1423 self
.mcpu
.assertLogIsEmpty()
1426 class TestLUClusterVerifyGroupVerifyGroupDRBDVersion(
1427 TestLUClusterVerifyGroupMethods
):
1429 def testEmptyNodeResult(self
, lu
):
1430 lu
._VerifyGroupDRBDVersion({})
1431 self
.mcpu
.assertLogIsEmpty()
1434 def testValidNodeResult(self
, lu
):
1435 lu
._VerifyGroupDRBDVersion(
1437 .AddSuccessfulNode(self
.master
, {
1438 constants
.NV_DRBDVERSION
: "8.3.0"
1441 self
.mcpu
.assertLogIsEmpty()
1444 def testDifferentVersions(self
, lu
):
1445 node1
= self
.cfg
.AddNewNode()
1446 lu
._VerifyGroupDRBDVersion(
1448 .AddSuccessfulNode(self
.master
, {
1449 constants
.NV_DRBDVERSION
: "8.3.0"
1451 .AddSuccessfulNode(node1
, {
1452 constants
.NV_DRBDVERSION
: "8.4.0"
1455 self
.mcpu
.assertLogContainsRegex("DRBD version mismatch: 8.3.0")
1456 self
.mcpu
.assertLogContainsRegex("DRBD version mismatch: 8.4.0")
1459 class TestLUClusterVerifyGroupVerifyGroupLVM(TestLUClusterVerifyGroupMethods
):
1461 def testNoVgName(self
, lu
):
1462 lu
._VerifyGroupLVM(None, None)
1463 self
.mcpu
.assertLogIsEmpty()
1466 def testNoExclusiveStorage(self
, lu
):
1467 lu
._VerifyGroupLVM(None, "mock_vg")
1468 self
.mcpu
.assertLogIsEmpty()
1471 def testNoPvInfo(self
, lu
):
1472 lu
._exclusive_storage
= True
1473 nimg
= cluster
.LUClusterVerifyGroup
.NodeImage()
1474 lu
._VerifyGroupLVM({self
.master
.uuid
: nimg
}, "mock_vg")
1475 self
.mcpu
.assertLogIsEmpty()
1478 def testValidPvInfos(self
, lu
):
1479 lu
._exclusive_storage
= True
1480 node2
= self
.cfg
.AddNewNode()
1481 nimg1
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master
.uuid
)
1482 nimg1
.pv_min
= 10000
1483 nimg1
.pv_max
= 10010
1484 nimg2
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=node2
.uuid
)
1486 nimg2
.pv_max
= 10005
1487 lu
._VerifyGroupLVM({self
.master
.uuid
: nimg1
, node2
.uuid
: nimg2
}, "mock_vg")
1488 self
.mcpu
.assertLogIsEmpty()
1491 class TestLUClusterVerifyGroupVerifyNodeBridges(
1492 TestLUClusterVerifyGroupMethods
):
1494 def testNoBridges(self
, lu
):
1495 lu
._VerifyNodeBridges(None, None, None)
1496 self
.mcpu
.assertLogIsEmpty()
1499 def testInvalidBridges(self
, lu
):
1500 for ndata
in [{}, {constants
.NV_BRIDGES
: ""}]:
1501 self
.mcpu
.ClearLogMessages()
1502 lu
._VerifyNodeBridges(self
.master
, ndata
, ["mock_bridge"])
1503 self
.mcpu
.assertLogContainsRegex("not return valid bridge information")
1505 self
.mcpu
.ClearLogMessages()
1506 lu
._VerifyNodeBridges(self
.master
, {constants
.NV_BRIDGES
: ["mock_bridge"]},
1508 self
.mcpu
.assertLogContainsRegex("missing bridge")
1511 class TestLUClusterVerifyGroupVerifyNodeUserScripts(
1512 TestLUClusterVerifyGroupMethods
):
1514 def testNoUserScripts(self
, lu
):
1515 lu
._VerifyNodeUserScripts(self
.master
, {})
1516 self
.mcpu
.assertLogContainsRegex("did not return user scripts information")
1519 def testBrokenUserScripts(self
, lu
):
1520 lu
._VerifyNodeUserScripts(self
.master
,
1521 {constants
.NV_USERSCRIPTS
: ["script"]})
1522 self
.mcpu
.assertLogContainsRegex("scripts not present or not executable")
1525 class TestLUClusterVerifyGroupVerifyNodeNetwork(
1526 TestLUClusterVerifyGroupMethods
):
1529 super(TestLUClusterVerifyGroupVerifyNodeNetwork
, self
).setUp()
1530 self
.VALID_NRESULT
= {
1531 constants
.NV_NODELIST
: {},
1532 constants
.NV_NODENETTEST
: {},
1533 constants
.NV_MASTERIP
: True
1537 def testEmptyNodeResult(self
, lu
):
1538 lu
._VerifyNodeNetwork(self
.master
, {})
1539 self
.mcpu
.assertLogContainsRegex(
1540 "node hasn't returned node ssh connectivity data")
1541 self
.mcpu
.assertLogContainsRegex(
1542 "node hasn't returned node tcp connectivity data")
1543 self
.mcpu
.assertLogContainsRegex(
1544 "node hasn't returned node master IP reachability data")
1547 def testValidResult(self
, lu
):
1548 lu
._VerifyNodeNetwork(self
.master
, self
.VALID_NRESULT
)
1549 self
.mcpu
.assertLogIsEmpty()
1552 def testSshProblem(self
, lu
):
1553 self
.VALID_NRESULT
.update({
1554 constants
.NV_NODELIST
: {
1555 "mock_node": "mock_error"
1558 lu
._VerifyNodeNetwork(self
.master
, self
.VALID_NRESULT
)
1559 self
.mcpu
.assertLogContainsRegex("ssh communication with node 'mock_node'")
1562 def testTcpProblem(self
, lu
):
1563 self
.VALID_NRESULT
.update({
1564 constants
.NV_NODENETTEST
: {
1565 "mock_node": "mock_error"
1568 lu
._VerifyNodeNetwork(self
.master
, self
.VALID_NRESULT
)
1569 self
.mcpu
.assertLogContainsRegex("tcp communication with node 'mock_node'")
1572 def testMasterIpNotReachable(self
, lu
):
1573 self
.VALID_NRESULT
.update({
1574 constants
.NV_MASTERIP
: False
1576 node1
= self
.cfg
.AddNewNode()
1577 lu
._VerifyNodeNetwork(self
.master
, self
.VALID_NRESULT
)
1578 self
.mcpu
.assertLogContainsRegex(
1579 "the master node cannot reach the master IP")
1581 self
.mcpu
.ClearLogMessages()
1582 lu
._VerifyNodeNetwork(node1
, self
.VALID_NRESULT
)
1583 self
.mcpu
.assertLogContainsRegex("cannot reach the master IP")
1586 class TestLUClusterVerifyGroupVerifyInstance(TestLUClusterVerifyGroupMethods
):
1588 super(TestLUClusterVerifyGroupVerifyInstance
, self
).setUp()
1590 self
.node1
= self
.cfg
.AddNewNode()
1591 self
.drbd_inst
= self
.cfg
.AddNewInstance(
1592 disks
=[self
.cfg
.CreateDisk(dev_type
=constants
.DT_DRBD8
,
1593 primary_node
=self
.master
,
1594 secondary_node
=self
.node1
)])
1595 self
.running_inst
= self
.cfg
.AddNewInstance(
1596 admin_state
=constants
.ADMINST_UP
, disks_active
=True)
1597 self
.diskless_inst
= self
.cfg
.AddNewInstance(disks
=[])
1600 cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
1601 self
.master_img
.volumes
= ["/".join(disk
.logical_id
)
1602 for inst
in [self
.running_inst
,
1605 self
.cfg
.GetInstanceDisks(inst
.uuid
)]
1606 drbd_inst_disks
= self
.cfg
.GetInstanceDisks(self
.drbd_inst
.uuid
)
1607 self
.master_img
.volumes
.extend(
1608 ["/".join(disk
.logical_id
) for disk
in drbd_inst_disks
[0].children
])
1609 self
.master_img
.instances
= [self
.running_inst
.uuid
]
1611 cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.node1
.uuid
)
1612 self
.node1_img
.volumes
= \
1613 ["/".join(disk
.logical_id
) for disk
in drbd_inst_disks
[0].children
]
1615 self
.master_uuid
: self
.master_img
,
1616 self
.node1
.uuid
: self
.node1_img
1618 running_inst_disks
= self
.cfg
.GetInstanceDisks(self
.running_inst
.uuid
)
1621 (True, objects
.BlockDevStatus(ldisk_status
=constants
.LDS_OKAY
))
1622 for _
in running_inst_disks
1627 def testDisklessInst(self
, lu
):
1628 lu
._VerifyInstance(self
.diskless_inst
, self
.node_imgs
, {})
1629 self
.mcpu
.assertLogIsEmpty()
1632 def testOfflineNode(self
, lu
):
1633 self
.master_img
.offline
= True
1634 lu
._VerifyInstance(self
.drbd_inst
, self
.node_imgs
, {})
1635 self
.mcpu
.assertLogIsEmpty()
1638 def testRunningOnOfflineNode(self
, lu
):
1639 self
.master_img
.offline
= True
1640 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, {})
1641 self
.mcpu
.assertLogContainsRegex(
1642 "instance is marked as running and lives on offline node")
1645 def testMissingVolume(self
, lu
):
1646 self
.master_img
.volumes
= []
1647 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, {})
1648 self
.mcpu
.assertLogContainsRegex("volume .* missing")
1651 def testRunningInstanceOnWrongNode(self
, lu
):
1652 self
.master_img
.instances
= []
1653 self
.diskless_inst
.admin_state
= constants
.ADMINST_UP
1654 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, {})
1655 self
.mcpu
.assertLogContainsRegex("instance not running on its primary node")
1658 def testRunningInstanceOnRightNode(self
, lu
):
1659 self
.master_img
.instances
= [self
.running_inst
.uuid
]
1660 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, {})
1661 self
.mcpu
.assertLogIsEmpty()
1664 def testValidDiskStatus(self
, lu
):
1665 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, self
.diskstatus
)
1666 self
.mcpu
.assertLogIsEmpty()
1669 def testDegradedDiskStatus(self
, lu
):
1670 self
.diskstatus
[self
.master_uuid
][0][1].is_degraded
= True
1671 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, self
.diskstatus
)
1672 self
.mcpu
.assertLogContainsRegex("instance .* is degraded")
1675 def testNotOkayDiskStatus(self
, lu
):
1676 self
.diskstatus
[self
.master_uuid
][0][1].ldisk_status
= constants
.LDS_FAULTY
1677 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, self
.diskstatus
)
1678 self
.mcpu
.assertLogContainsRegex("instance .* state is 'faulty'")
1681 def testExclusiveStorageWithInvalidInstance(self
, lu
):
1682 self
.master
.ndparams
[constants
.ND_EXCLUSIVE_STORAGE
] = True
1683 lu
._VerifyInstance(self
.drbd_inst
, self
.node_imgs
, self
.diskstatus
)
1684 self
.mcpu
.assertLogContainsRegex(
1685 "instance has template drbd, which is not supported")
1688 def testExclusiveStorageWithValidInstance(self
, lu
):
1689 self
.master
.ndparams
[constants
.ND_EXCLUSIVE_STORAGE
] = True
1690 running_inst_disks
= self
.cfg
.GetInstanceDisks(self
.running_inst
.uuid
)
1691 running_inst_disks
[0].spindles
= 1
1692 feedback_fn
= lambda _
: None
1693 self
.cfg
.Update(running_inst_disks
[0], feedback_fn
)
1694 lu
._VerifyInstance(self
.running_inst
, self
.node_imgs
, self
.diskstatus
)
1695 self
.mcpu
.assertLogIsEmpty()
1698 def testDrbdInTwoGroups(self
, lu
):
1699 group
= self
.cfg
.AddNewNodeGroup()
1700 self
.node1
.group
= group
.uuid
1701 lu
._VerifyInstance(self
.drbd_inst
, self
.node_imgs
, self
.diskstatus
)
1702 self
.mcpu
.assertLogContainsRegex(
1703 "instance has primary and secondary nodes in different groups")
1706 def testOfflineSecondary(self
, lu
):
1707 self
.node1_img
.offline
= True
1708 lu
._VerifyInstance(self
.drbd_inst
, self
.node_imgs
, self
.diskstatus
)
1709 self
.mcpu
.assertLogContainsRegex("instance has offline secondary node\(s\)")
1712 class TestLUClusterVerifyGroupVerifyOrphanVolumes(
1713 TestLUClusterVerifyGroupMethods
):
1715 def testOrphanedVolume(self
, lu
):
1716 master_img
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
1717 master_img
.volumes
= [
1718 "mock_vg/disk_0", # Required, present, no error
1719 "mock_vg/disk_1", # Unknown, present, orphan
1720 "mock_vg/disk_2", # Reserved, present, no error
1721 "other_vg/disk_0", # Required, present, no error
1722 "other_vg/disk_1", # Unknown, present, no error
1725 self
.master_uuid
: master_img
1728 self
.master_uuid
: ["mock_vg/disk_0", "other_vg/disk_0", "other_vg/disk_1"]
1731 lu
._VerifyOrphanVolumes("mock_vg", node_vol_should
, node_imgs
,
1732 utils
.FieldSet("mock_vg/disk_2"))
1733 self
.mcpu
.assertLogContainsRegex("volume mock_vg/disk_1 is unknown")
1734 self
.mcpu
.assertLogDoesNotContainRegex("volume mock_vg/disk_0 is unknown")
1735 self
.mcpu
.assertLogDoesNotContainRegex("volume mock_vg/disk_2 is unknown")
1736 self
.mcpu
.assertLogDoesNotContainRegex("volume other_vg/disk_0 is unknown")
1737 self
.mcpu
.assertLogDoesNotContainRegex("volume other_vg/disk_1 is unknown")
1740 class TestLUClusterVerifyGroupVerifyNPlusOneMemory(
1741 TestLUClusterVerifyGroupMethods
):
1743 def testN1Failure(self
, lu
):
1744 group1
= self
.cfg
.AddNewNodeGroup()
1746 node1
= self
.cfg
.AddNewNode()
1747 node2
= self
.cfg
.AddNewNode(group
=group1
)
1748 node3
= self
.cfg
.AddNewNode()
1750 inst1
= self
.cfg
.AddNewInstance()
1751 inst2
= self
.cfg
.AddNewInstance()
1752 inst3
= self
.cfg
.AddNewInstance()
1754 node1_img
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=node1
.uuid
)
1756 self
.master_uuid
: [inst1
.uuid
, inst2
.uuid
, inst3
.uuid
]
1759 node2_img
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=node2
.uuid
)
1761 node3_img
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=node3
.uuid
)
1762 node3_img
.offline
= True
1765 node1
.uuid
: node1_img
,
1766 node2
.uuid
: node2_img
,
1767 node3
.uuid
: node3_img
1770 lu
._VerifyNPlusOneMemory(node_imgs
, self
.cfg
.GetAllInstancesInfo())
1771 self
.mcpu
.assertLogContainsRegex(
1772 "not enough memory to accomodate instance failovers")
1774 self
.mcpu
.ClearLogMessages()
1775 node1_img
.mfree
= 1000
1776 lu
._VerifyNPlusOneMemory(node_imgs
, self
.cfg
.GetAllInstancesInfo())
1777 self
.mcpu
.assertLogIsEmpty()
1780 class TestLUClusterVerifyGroupVerifyFiles(TestLUClusterVerifyGroupMethods
):
1783 node1
= self
.cfg
.AddNewNode(master_candidate
=False, offline
=False,
1785 node2
= self
.cfg
.AddNewNode(master_candidate
=True, vm_capable
=False)
1786 node3
= self
.cfg
.AddNewNode(master_candidate
=False, offline
=False,
1788 node4
= self
.cfg
.AddNewNode(master_candidate
=False, offline
=False,
1790 node5
= self
.cfg
.AddNewNode(master_candidate
=False, offline
=True)
1792 nodeinfo
= [self
.master
, node1
, node2
, node3
, node4
, node5
]
1794 pathutils
.CLUSTER_DOMAIN_SECRET_FILE
,
1795 pathutils
.RAPI_CERT_FILE
,
1796 pathutils
.RAPI_USERS_FILE
,
1799 pathutils
.RAPI_USERS_FILE
,
1800 hv_xen
.XL_CONFIG_FILE
,
1801 pathutils
.VNC_PASSWORD_FILE
,
1804 pathutils
.CLUSTER_CONF_FILE
,
1807 hv_xen
.XEND_CONFIG_FILE
,
1808 hv_xen
.XL_CONFIG_FILE
,
1809 pathutils
.VNC_PASSWORD_FILE
,
1811 nvinfo
= RpcResultsBuilder() \
1812 .AddSuccessfulNode(self
.master
, {
1813 constants
.NV_FILELIST
: {
1814 pathutils
.CLUSTER_CONF_FILE
: "82314f897f38b35f9dab2f7c6b1593e0",
1815 pathutils
.RAPI_CERT_FILE
: "babbce8f387bc082228e544a2146fee4",
1816 pathutils
.CLUSTER_DOMAIN_SECRET_FILE
: "cds-47b5b3f19202936bb4",
1817 hv_xen
.XEND_CONFIG_FILE
: "b4a8a824ab3cac3d88839a9adeadf310",
1818 hv_xen
.XL_CONFIG_FILE
: "77935cee92afd26d162f9e525e3d49b9"
1820 .AddSuccessfulNode(node1
, {
1821 constants
.NV_FILELIST
: {
1822 pathutils
.RAPI_CERT_FILE
: "97f0356500e866387f4b84233848cc4a",
1823 hv_xen
.XEND_CONFIG_FILE
: "b4a8a824ab3cac3d88839a9adeadf310",
1826 .AddSuccessfulNode(node2
, {
1827 constants
.NV_FILELIST
: {
1828 pathutils
.RAPI_CERT_FILE
: "97f0356500e866387f4b84233848cc4a",
1829 pathutils
.CLUSTER_DOMAIN_SECRET_FILE
: "cds-47b5b3f19202936bb4",
1832 .AddSuccessfulNode(node3
, {
1833 constants
.NV_FILELIST
: {
1834 pathutils
.RAPI_CERT_FILE
: "97f0356500e866387f4b84233848cc4a",
1835 pathutils
.CLUSTER_CONF_FILE
: "conf-a6d4b13e407867f7a7b4f0f232a8f527",
1836 pathutils
.CLUSTER_DOMAIN_SECRET_FILE
: "cds-47b5b3f19202936bb4",
1837 pathutils
.RAPI_USERS_FILE
: "rapiusers-ea3271e8d810ef3",
1838 hv_xen
.XL_CONFIG_FILE
: "77935cee92afd26d162f9e525e3d49b9"
1841 .AddSuccessfulNode(node4
, {}) \
1842 .AddOfflineNode(node5
) \
1844 assert set(nvinfo
.keys()) == set(map(operator
.attrgetter("uuid"), nodeinfo
))
1846 lu
._VerifyFiles(nodeinfo
, self
.master_uuid
, nvinfo
,
1847 (files_all
, files_opt
, files_mc
, files_vm
))
1850 "File %s found with 2 different checksums (variant 1 on"
1851 " %s, %s, %s; variant 2 on %s)" %
1852 (pathutils
.RAPI_CERT_FILE
, node1
.name
, node2
.name
, node3
.name
,
1854 "File %s is missing from node(s) %s" %
1855 (pathutils
.CLUSTER_DOMAIN_SECRET_FILE
, node1
.name
),
1856 "File %s should not exist on node(s) %s" %
1857 (pathutils
.CLUSTER_CONF_FILE
, node3
.name
),
1858 "File %s is missing from node(s) %s" %
1859 (hv_xen
.XEND_CONFIG_FILE
, node3
.name
),
1860 "File %s is missing from node(s) %s" %
1861 (pathutils
.CLUSTER_CONF_FILE
, node2
.name
),
1862 "File %s found with 2 different checksums (variant 1 on"
1863 " %s; variant 2 on %s)" %
1864 (pathutils
.CLUSTER_CONF_FILE
, self
.master
.name
, node3
.name
),
1865 "File %s is optional, but it must exist on all or no nodes (not"
1866 " found on %s, %s, %s)" %
1867 (pathutils
.RAPI_USERS_FILE
, self
.master
.name
, node1
.name
, node2
.name
),
1868 "File %s is optional, but it must exist on all or no nodes (not"
1869 " found on %s)" % (hv_xen
.XL_CONFIG_FILE
, node1
.name
),
1870 "Node did not return file checksum data",
1873 self
.assertEqual(len(self
.mcpu
.GetLogMessages()), len(expected_msgs
))
1874 for expected_msg
in expected_msgs
:
1875 self
.mcpu
.assertLogContainsInLine(expected_msg
)
1878 class TestLUClusterVerifyGroupVerifyNodeOs(TestLUClusterVerifyGroupMethods
):
1880 def testUpdateNodeOsInvalidNodeResult(self
, lu
):
1881 for ndata
in [{}, {constants
.NV_OSLIST
: ""}, {constants
.NV_OSLIST
: [""]},
1882 {constants
.NV_OSLIST
: [["1", "2"]]}]:
1883 self
.mcpu
.ClearLogMessages()
1884 nimage
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
1885 lu
._UpdateNodeOS(self
.master
, ndata
, nimage
)
1886 self
.mcpu
.assertLogContainsRegex("node hasn't returned valid OS data")
1889 def testUpdateNodeOsValidNodeResult(self
, lu
):
1891 constants
.NV_OSLIST
: [
1892 ["mock_OS", "/mocked/path", True, "", ["default"], [],
1893 [constants
.OS_API_V20
], True],
1894 ["Another_Mock", "/random", True, "", ["var1", "var2"],
1895 [{"param1": "val1"}, {"param2": "val2"}], constants
.OS_API_VERSIONS
,
1899 nimage
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
1900 lu
._UpdateNodeOS(self
.master
, ndata
, nimage
)
1901 self
.mcpu
.assertLogIsEmpty()
1904 def testVerifyNodeOs(self
, lu
):
1905 node
= self
.cfg
.AddNewNode()
1906 nimg_root
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
1907 nimg
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=node
.uuid
)
1909 nimg_root
.os_fail
= False
1910 nimg_root
.oslist
= {
1911 "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1912 set([constants
.OS_API_V20
]), True)],
1913 "broken_base_os": [("/broken", False, "", set(), set(),
1914 set([constants
.OS_API_V20
]), True)],
1915 "only_on_root": [("/random", True, "", set(), set(), set(), True)],
1916 "diffing_os": [("/pinky", True, "", set(["var1", "var2"]),
1917 set([("param1", "val1"), ("param2", "val2")]),
1918 set([constants
.OS_API_V20
]), True)],
1919 "trust_os": [("/trust/mismatch", True, "", set(), set(), set(), True)],
1921 nimg
.os_fail
= False
1923 "mock_os": [("/mocked/path", True, "", set(["default"]), set(),
1924 set([constants
.OS_API_V20
]), True)],
1925 "only_on_test": [("/random", True, "", set(), set(), set(), True)],
1926 "diffing_os": [("/bunny", True, "", set(["var1", "var3"]),
1927 set([("param1", "val1"), ("param3", "val3")]),
1928 set([constants
.OS_API_V15
]), True)],
1929 "broken_os": [("/broken", False, "", set(), set(),
1930 set([constants
.OS_API_V20
]), True)],
1932 ("/multi1", True, "", set(), set(), set([constants
.OS_API_V20
]), True),
1933 ("/multi2", True, "", set(), set(), set([constants
.OS_API_V20
]), True)],
1934 "trust_os": [("/trust/mismatch", True, "", set(), set(), set(), False)],
1937 lu
._VerifyNodeOS(node
, nimg
, nimg_root
)
1940 "Extra OS only_on_test not present on reference node",
1941 "OSes present on reference node .* but missing on this node:" +
1943 "OS API version for diffing_os differs",
1944 "OS variants list for diffing_os differs",
1945 "OS parameters for diffing_os differs",
1946 "Invalid OS broken_os",
1947 "Extra OS broken_os not present on reference node",
1948 "OS 'multi_entries' has multiple entries",
1949 "Extra OS multi_entries not present on reference node",
1950 "OS trusted for trust_os differs from reference node "
1953 self
.assertEqual(len(expected_msgs
), len(self
.mcpu
.GetLogMessages()))
1954 for expected_msg
in expected_msgs
:
1955 self
.mcpu
.assertLogContainsRegex(expected_msg
)
1958 class TestLUClusterVerifyGroupVerifyAcceptedFileStoragePaths(
1959 TestLUClusterVerifyGroupMethods
):
1961 def testNotMaster(self
, lu
):
1962 lu
._VerifyAcceptedFileStoragePaths(self
.master
, {}, False)
1963 self
.mcpu
.assertLogIsEmpty()
1966 def testNotMasterButRetunedValue(self
, lu
):
1967 lu
._VerifyAcceptedFileStoragePaths(
1968 self
.master
, {constants
.NV_ACCEPTED_STORAGE_PATHS
: []}, False)
1969 self
.mcpu
.assertLogContainsRegex(
1970 "Node should not have returned forbidden file storage paths")
1973 def testMasterInvalidNodeResult(self
, lu
):
1974 lu
._VerifyAcceptedFileStoragePaths(self
.master
, {}, True)
1975 self
.mcpu
.assertLogContainsRegex(
1976 "Node did not return forbidden file storage paths")
1979 def testMasterForbiddenPaths(self
, lu
):
1980 lu
._VerifyAcceptedFileStoragePaths(
1981 self
.master
, {constants
.NV_ACCEPTED_STORAGE_PATHS
: ["/forbidden"]}, True)
1982 self
.mcpu
.assertLogContainsRegex("Found forbidden file storage paths")
1985 def testMasterSuccess(self
, lu
):
1986 lu
._VerifyAcceptedFileStoragePaths(
1987 self
.master
, {constants
.NV_ACCEPTED_STORAGE_PATHS
: []}, True)
1988 self
.mcpu
.assertLogIsEmpty()
1991 class TestLUClusterVerifyGroupVerifyStoragePaths(
1992 TestLUClusterVerifyGroupMethods
):
1994 def testVerifyFileStoragePathsSuccess(self
, lu
):
1995 lu
._VerifyFileStoragePaths(self
.master
, {})
1996 self
.mcpu
.assertLogIsEmpty()
1999 def testVerifyFileStoragePathsFailure(self
, lu
):
2000 lu
._VerifyFileStoragePaths(self
.master
,
2001 {constants
.NV_FILE_STORAGE_PATH
: "/fail/path"})
2002 self
.mcpu
.assertLogContainsRegex(
2003 "The configured file storage path is unusable")
2006 def testVerifySharedFileStoragePathsSuccess(self
, lu
):
2007 lu
._VerifySharedFileStoragePaths(self
.master
, {})
2008 self
.mcpu
.assertLogIsEmpty()
2011 def testVerifySharedFileStoragePathsFailure(self
, lu
):
2012 lu
._VerifySharedFileStoragePaths(
2013 self
.master
, {constants
.NV_SHARED_FILE_STORAGE_PATH
: "/fail/path"})
2014 self
.mcpu
.assertLogContainsRegex(
2015 "The configured sharedfile storage path is unusable")
2018 class TestLUClusterVerifyGroupVerifyOob(TestLUClusterVerifyGroupMethods
):
2020 def testEmptyResult(self
, lu
):
2021 lu
._VerifyOob(self
.master
, {})
2022 self
.mcpu
.assertLogIsEmpty()
2025 def testErrorResults(self
, lu
):
2026 lu
._VerifyOob(self
.master
, {constants
.NV_OOB_PATHS
: ["path1", "path2"]})
2027 self
.mcpu
.assertLogContainsRegex("path1")
2028 self
.mcpu
.assertLogContainsRegex("path2")
2031 class TestLUClusterVerifyGroupUpdateNodeVolumes(
2032 TestLUClusterVerifyGroupMethods
):
2034 super(TestLUClusterVerifyGroupUpdateNodeVolumes
, self
).setUp()
2035 self
.nimg
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
2038 def testNoVgName(self
, lu
):
2039 lu
._UpdateNodeVolumes(self
.master
, {}, self
.nimg
, None)
2040 self
.mcpu
.assertLogIsEmpty()
2041 self
.assertTrue(self
.nimg
.lvm_fail
)
2044 def testErrorMessage(self
, lu
):
2045 lu
._UpdateNodeVolumes(self
.master
, {constants
.NV_LVLIST
: "mock error"},
2046 self
.nimg
, "mock_vg")
2047 self
.mcpu
.assertLogContainsRegex("LVM problem on node: mock error")
2048 self
.assertTrue(self
.nimg
.lvm_fail
)
2051 def testInvalidNodeResult(self
, lu
):
2052 lu
._UpdateNodeVolumes(self
.master
, {constants
.NV_LVLIST
: [1, 2, 3]},
2053 self
.nimg
, "mock_vg")
2054 self
.mcpu
.assertLogContainsRegex("rpc call to node failed")
2055 self
.assertTrue(self
.nimg
.lvm_fail
)
2058 def testValidNodeResult(self
, lu
):
2059 lu
._UpdateNodeVolumes(self
.master
, {constants
.NV_LVLIST
: {}},
2060 self
.nimg
, "mock_vg")
2061 self
.mcpu
.assertLogIsEmpty()
2062 self
.assertFalse(self
.nimg
.lvm_fail
)
2065 class TestLUClusterVerifyGroupUpdateNodeInstances(
2066 TestLUClusterVerifyGroupMethods
):
2068 super(TestLUClusterVerifyGroupUpdateNodeInstances
, self
).setUp()
2069 self
.nimg
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
2072 def testInvalidNodeResult(self
, lu
):
2073 lu
._UpdateNodeInstances(self
.master
, {}, self
.nimg
)
2074 self
.mcpu
.assertLogContainsRegex("rpc call to node failed")
2077 def testValidNodeResult(self
, lu
):
2078 inst
= self
.cfg
.AddNewInstance()
2079 lu
._UpdateNodeInstances(self
.master
,
2080 {constants
.NV_INSTANCELIST
: [inst
.name
]},
2082 self
.mcpu
.assertLogIsEmpty()
2085 class TestLUClusterVerifyGroupUpdateNodeInfo(TestLUClusterVerifyGroupMethods
):
2087 super(TestLUClusterVerifyGroupUpdateNodeInfo
, self
).setUp()
2088 self
.nimg
= cluster
.LUClusterVerifyGroup
.NodeImage(uuid
=self
.master_uuid
)
2089 self
.valid_hvresult
= {constants
.NV_HVINFO
: {"memory_free": 1024}}
2092 def testInvalidHvNodeResult(self
, lu
):
2093 for ndata
in [{}, {constants
.NV_HVINFO
: ""}]:
2094 self
.mcpu
.ClearLogMessages()
2095 lu
._UpdateNodeInfo(self
.master
, ndata
, self
.nimg
, None)
2096 self
.mcpu
.assertLogContainsRegex("rpc call to node failed")
2099 def testInvalidMemoryFreeHvNodeResult(self
, lu
):
2100 lu
._UpdateNodeInfo(self
.master
,
2101 {constants
.NV_HVINFO
: {"memory_free": "abc"}},
2103 self
.mcpu
.assertLogContainsRegex(
2104 "node returned invalid nodeinfo, check hypervisor")
2107 def testValidHvNodeResult(self
, lu
):
2108 lu
._UpdateNodeInfo(self
.master
, self
.valid_hvresult
, self
.nimg
, None)
2109 self
.mcpu
.assertLogIsEmpty()
2112 def testInvalidVgNodeResult(self
, lu
):
2113 for vgdata
in [[], ""]:
2114 self
.mcpu
.ClearLogMessages()
2115 ndata
= {constants
.NV_VGLIST
: vgdata
}
2116 ndata
.update(self
.valid_hvresult
)
2117 lu
._UpdateNodeInfo(self
.master
, ndata
, self
.nimg
, "mock_vg")
2118 self
.mcpu
.assertLogContainsRegex(
2119 "node didn't return data for the volume group 'mock_vg'")
2122 def testInvalidDiskFreeVgNodeResult(self
, lu
):
2123 self
.valid_hvresult
.update({
2124 constants
.NV_VGLIST
: {"mock_vg": "abc"}
2126 lu
._UpdateNodeInfo(self
.master
, self
.valid_hvresult
, self
.nimg
, "mock_vg")
2127 self
.mcpu
.assertLogContainsRegex(
2128 "node returned invalid LVM info, check LVM status")
2131 def testValidVgNodeResult(self
, lu
):
2132 self
.valid_hvresult
.update({
2133 constants
.NV_VGLIST
: {"mock_vg": 10000}
2135 lu
._UpdateNodeInfo(self
.master
, self
.valid_hvresult
, self
.nimg
, "mock_vg")
2136 self
.mcpu
.assertLogIsEmpty()
2139 class TestLUClusterVerifyGroupCollectDiskInfo(TestLUClusterVerifyGroupMethods
):
2141 super(TestLUClusterVerifyGroupCollectDiskInfo
, self
).setUp()
2143 self
.node1
= self
.cfg
.AddNewNode()
2144 self
.node2
= self
.cfg
.AddNewNode()
2145 self
.node3
= self
.cfg
.AddNewNode()
2147 self
.diskless_inst
= \
2148 self
.cfg
.AddNewInstance(primary_node
=self
.node1
,
2149 disk_template
=constants
.DT_DISKLESS
)
2151 self
.cfg
.AddNewInstance(primary_node
=self
.node2
,
2152 disk_template
=constants
.DT_PLAIN
)
2154 self
.cfg
.AddNewInstance(primary_node
=self
.node3
,
2155 secondary_node
=self
.node2
,
2156 disk_template
=constants
.DT_DRBD8
)
2158 self
.node1_img
= cluster
.LUClusterVerifyGroup
.NodeImage(
2159 uuid
=self
.node1
.uuid
)
2160 self
.node1_img
.pinst
= [self
.diskless_inst
.uuid
]
2161 self
.node1_img
.sinst
= []
2162 self
.node2_img
= cluster
.LUClusterVerifyGroup
.NodeImage(
2163 uuid
=self
.node2
.uuid
)
2164 self
.node2_img
.pinst
= [self
.plain_inst
.uuid
]
2165 self
.node2_img
.sinst
= [self
.drbd_inst
.uuid
]
2166 self
.node3_img
= cluster
.LUClusterVerifyGroup
.NodeImage(
2167 uuid
=self
.node3
.uuid
)
2168 self
.node3_img
.pinst
= [self
.drbd_inst
.uuid
]
2169 self
.node3_img
.sinst
= []
2171 self
.node_images
= {
2172 self
.node1
.uuid
: self
.node1_img
,
2173 self
.node2
.uuid
: self
.node2_img
,
2174 self
.node3
.uuid
: self
.node3_img
2177 self
.node_uuids
= [self
.node1
.uuid
, self
.node2
.uuid
, self
.node3
.uuid
]
2180 def testSuccessfulRun(self
, lu
):
2181 self
.rpc
.call_blockdev_getmirrorstatus_multi
.return_value
= \
2182 RpcResultsBuilder() \
2183 .AddSuccessfulNode(self
.node2
, [(True, ""), (True, "")]) \
2184 .AddSuccessfulNode(self
.node3
, [(True, "")]) \
2187 lu
._CollectDiskInfo(self
.node_uuids
, self
.node_images
,
2188 self
.cfg
.GetAllInstancesInfo())
2190 self
.mcpu
.assertLogIsEmpty()
2193 def testOfflineAndFailingNodes(self
, lu
):
2194 self
.rpc
.call_blockdev_getmirrorstatus_multi
.return_value
= \
2195 RpcResultsBuilder() \
2196 .AddOfflineNode(self
.node2
) \
2197 .AddFailedNode(self
.node3
) \
2200 lu
._CollectDiskInfo(self
.node_uuids
, self
.node_images
,
2201 self
.cfg
.GetAllInstancesInfo())
2203 self
.mcpu
.assertLogContainsRegex("while getting disk information")
2206 def testInvalidNodeResult(self
, lu
):
2207 self
.rpc
.call_blockdev_getmirrorstatus_multi
.return_value
= \
2208 RpcResultsBuilder() \
2209 .AddSuccessfulNode(self
.node2
, [(True,), (False,)]) \
2210 .AddSuccessfulNode(self
.node3
, [""]) \
2213 lu
._CollectDiskInfo(self
.node_uuids
, self
.node_images
,
2214 self
.cfg
.GetAllInstancesInfo())
2215 # logging is not performed through mcpu
2216 self
.mcpu
.assertLogIsEmpty()
2219 class TestLUClusterVerifyGroupHooksCallBack(TestLUClusterVerifyGroupMethods
):
2221 super(TestLUClusterVerifyGroupHooksCallBack
, self
).setUp()
2223 self
.feedback_fn
= lambda _
: None
2225 def PrepareLU(self
, lu
):
2226 super(TestLUClusterVerifyGroupHooksCallBack
, self
).PrepareLU(lu
)
2228 lu
.my_node_uuids
= list(self
.cfg
.GetAllNodesInfo().keys())
2231 def testEmptyGroup(self
, lu
):
2232 lu
.my_node_uuids
= []
2233 lu
.HooksCallBack(constants
.HOOKS_PHASE_POST
, None, self
.feedback_fn
, None)
2236 def testFailedResult(self
, lu
):
2237 lu
.HooksCallBack(constants
.HOOKS_PHASE_POST
,
2238 RpcResultsBuilder(use_node_names
=True)
2239 .AddFailedNode(self
.master
).Build(),
2242 self
.mcpu
.assertLogContainsRegex("Communication failure in hooks execution")
2245 def testOfflineNode(self
, lu
):
2246 lu
.HooksCallBack(constants
.HOOKS_PHASE_POST
,
2247 RpcResultsBuilder(use_node_names
=True)
2248 .AddOfflineNode(self
.master
).Build(),
2253 def testValidResult(self
, lu
):
2254 lu
.HooksCallBack(constants
.HOOKS_PHASE_POST
,
2255 RpcResultsBuilder(use_node_names
=True)
2256 .AddSuccessfulNode(self
.master
,
2258 constants
.HKR_SUCCESS
,
2265 def testFailedScriptResult(self
, lu
):
2266 lu
.HooksCallBack(constants
.HOOKS_PHASE_POST
,
2267 RpcResultsBuilder(use_node_names
=True)
2268 .AddSuccessfulNode(self
.master
,
2275 self
.mcpu
.assertLogContainsRegex("Script mock_script failed")
2278 class TestLUClusterVerifyDisks(CmdlibTestCase
):
2279 def testVerifyDisks(self
):
2280 op
= opcodes
.OpClusterVerifyDisks()
2281 result
= self
.ExecOpCode(op
)
2283 self
.assertEqual(1, len(result
["jobs"]))
2286 class TestLUClusterRenewCrypto(CmdlibTestCase
):
2289 super(TestLUClusterRenewCrypto
, self
).setUp()
2290 self
._node_cert
= self
._CreateTempFile()
2291 shutil
.copy(testutils
.TestDataFilename("cert1.pem"), self
._node_cert
)
2292 self
._client_node_cert
= self
._CreateTempFile()
2293 shutil
.copy(testutils
.TestDataFilename("cert2.pem"), self
._client_node_cert
)
2294 self
._client_node_cert_digest
= \
2295 "BF:24:F7:57:50:60:43:87:83:E3:0D:7E:EF:DD:14:6C:13:43:20:4E"
2298 super(TestLUClusterRenewCrypto
, self
).tearDown()
2300 def _GetFakeDigest(self
, uuid
):
2301 """Creates a fake SSL digest depending on the UUID of a node.
2304 @param uuid: node UUID
2305 @returns: a string impersonating a SSL digest
2308 return "FA:KE:%s:%s:%s:%s" % (uuid
[0:2], uuid
[2:4], uuid
[4:6], uuid
[6:8])
2310 def _InitPathutils(self
, pathutils
):
2311 """Patch pathutils to point to temporary files.
2314 pathutils
.NODED_CERT_FILE
= self
._node_cert
2315 pathutils
.NODED_CLIENT_CERT_FILE
= self
._client_node_cert
2317 def _AssertCertFiles(self
, pathutils
):
2318 """Check if the correct certificates exist and don't exist on the master.
2321 self
.assertTrue(os
.path
.exists(pathutils
.NODED_CERT_FILE
))
2322 self
.assertTrue(os
.path
.exists(pathutils
.NODED_CLIENT_CERT_FILE
))
2324 def _CompletelySuccessfulRpc(self
, node_uuid
, _
):
2325 """Fake RPC call which always returns successfully.
2328 return self
.RpcResultsBuilder() \
2329 .CreateSuccessfulNodeResult(node_uuid
,
2330 [(constants
.CRYPTO_TYPE_SSL_DIGEST
,
2331 self
._GetFakeDigest(node_uuid
))])
2333 @patchPathutils("cluster")
2334 def testSuccessfulCase(self
, pathutils
):
2335 self
._InitPathutils(pathutils
)
2337 # create a few non-master, online nodes
2339 for _
in range(num_nodes
):
2340 self
.cfg
.AddNewNode()
2341 self
.rpc
.call_node_crypto_tokens
= self
._CompletelySuccessfulRpc
2343 op
= opcodes
.OpClusterRenewCrypto()
2346 self
._AssertCertFiles(pathutils
)
2348 # Check if we have the correct digests in the configuration
2349 cluster
= self
.cfg
.GetClusterInfo()
2350 self
.assertEqual(num_nodes
+ 1, len(cluster
.candidate_certs
))
2351 nodes
= self
.cfg
.GetAllNodesInfo()
2352 master_uuid
= self
.cfg
.GetMasterNode()
2353 for (node_uuid
, _
) in nodes
.items():
2354 if node_uuid
== master_uuid
:
2355 # The master digest is from the actual test certificate.
2356 self
.assertEqual(self
._client_node_cert_digest
,
2357 cluster
.candidate_certs
[node_uuid
])
2359 # The non-master nodes have the fake digest from the
2361 expected_digest
= self
._GetFakeDigest(node_uuid
)
2362 self
.assertEqual(expected_digest
, cluster
.candidate_certs
[node_uuid
])
2364 def _partiallyFailingRpc(self
, node_uuid
, _
):
2365 if node_uuid
== self
._failed_node
:
2366 return self
.RpcResultsBuilder() \
2367 .CreateFailedNodeResult(node_uuid
)
2369 return self
.RpcResultsBuilder() \
2370 .CreateSuccessfulNodeResult(node_uuid
,
2371 [(constants
.CRYPTO_TYPE_SSL_DIGEST
, self
._GetFakeDigest(node_uuid
))])
2373 @patchPathutils("cluster")
2374 def testNonMasterFails(self
, pathutils
):
2375 self
._InitPathutils(pathutils
)
2377 # create a few non-master, online nodes
2379 for _
in range(num_nodes
):
2380 self
.cfg
.AddNewNode()
2381 nodes
= self
.cfg
.GetAllNodesInfo()
2383 # pick one node as the failing one
2384 master_uuid
= self
.cfg
.GetMasterNode()
2385 self
._failed_node
= [node_uuid
for node_uuid
in nodes
2386 if node_uuid
!= master_uuid
][1]
2387 self
.rpc
.call_node_crypto_tokens
= self
._partiallyFailingRpc
2389 op
= opcodes
.OpClusterRenewCrypto()
2392 self
._AssertCertFiles(pathutils
)
2394 # Check if we have the correct digests in the configuration
2395 cluster
= self
.cfg
.GetClusterInfo()
2396 # There should be one digest missing.
2397 self
.assertEqual(num_nodes
, len(cluster
.candidate_certs
))
2398 nodes
= self
.cfg
.GetAllNodesInfo()
2399 for (node_uuid
, _
) in nodes
.items():
2400 if node_uuid
== self
._failed_node
:
2401 self
.assertTrue(node_uuid
not in cluster
.candidate_certs
)
2403 self
.assertTrue(node_uuid
in cluster
.candidate_certs
)
2405 @patchPathutils("cluster")
2406 def testOfflineNodes(self
, pathutils
):
2407 self
._InitPathutils(pathutils
)
2409 # create a few non-master, online nodes
2412 for i
in range(num_nodes
):
2413 # Pick one node to be offline.
2414 self
.cfg
.AddNewNode(offline
=(i
==offline_index
))
2415 self
.rpc
.call_node_crypto_tokens
= self
._CompletelySuccessfulRpc
2417 op
= opcodes
.OpClusterRenewCrypto()
2420 self
._AssertCertFiles(pathutils
)
2422 # Check if we have the correct digests in the configuration
2423 cluster
= self
.cfg
.GetClusterInfo()
2424 # There should be one digest missing.
2425 self
.assertEqual(num_nodes
, len(cluster
.candidate_certs
))
2426 nodes
= self
.cfg
.GetAllNodesInfo()
2427 for (node_uuid
, node_info
) in nodes
.items():
2428 if node_info
.offline
== True:
2429 self
.assertTrue(node_uuid
not in cluster
.candidate_certs
)
2431 self
.assertTrue(node_uuid
in cluster
.candidate_certs
)
2433 def _RpcSuccessfulAfterRetries(self
, node_uuid
, _
):
2434 if self
._retries
< self
._max_retries
:
2436 return self
.RpcResultsBuilder() \
2437 .CreateFailedNodeResult(node_uuid
)
2439 return self
.RpcResultsBuilder() \
2440 .CreateSuccessfulNodeResult(node_uuid
,
2441 [(constants
.CRYPTO_TYPE_SSL_DIGEST
, self
._GetFakeDigest(node_uuid
))])
2443 def _RpcSuccessfulAfterRetriesNonMaster(self
, node_uuid
, _
):
2444 if self
._retries
< self
._max_retries
and node_uuid
!= self
._master_uuid
:
2446 return self
.RpcResultsBuilder() \
2447 .CreateFailedNodeResult(node_uuid
)
2449 return self
.RpcResultsBuilder() \
2450 .CreateSuccessfulNodeResult(node_uuid
,
2451 [(constants
.CRYPTO_TYPE_SSL_DIGEST
, self
._GetFakeDigest(node_uuid
))])
2453 def _NonMasterRetries(self
, pathutils
, max_retries
):
2454 self
._InitPathutils(pathutils
)
2456 self
._master_uuid
= self
.cfg
.GetMasterNode()
2457 self
._max_retries
= max_retries
2459 self
.rpc
.call_node_crypto_tokens
= self
._RpcSuccessfulAfterRetriesNonMaster
2461 # Add one non-master node
2462 self
.cfg
.AddNewNode()
2464 op
= opcodes
.OpClusterRenewCrypto()
2467 self
._AssertCertFiles(pathutils
)
2469 return self
.cfg
.GetClusterInfo()
2471 @patchPathutils("cluster")
2472 def testNonMasterRetriesSuccess(self
, pathutils
):
2473 cluster
= self
._NonMasterRetries(pathutils
, 2)
2474 self
.assertEqual(2, len(cluster
.candidate_certs
.values()))
2476 @patchPathutils("cluster")
2477 def testNonMasterRetriesFail(self
, pathutils
):
2478 cluster
= self
._NonMasterRetries(pathutils
, 5)
2480 # Only the master digest should be in the cert list
2481 self
.assertEqual(1, len(cluster
.candidate_certs
.values()))
2482 self
.assertTrue(self
._master_uuid
in cluster
.candidate_certs
)
2485 if __name__
== "__main__":
2486 testutils
.GanetiTestProgram()