Revision 75bf3149
b/lib/backend.py | ||
---|---|---|
726 | 726 |
return res |
727 | 727 |
|
728 | 728 |
|
729 |
def _VerifyHypervisors(what, vm_capable, result, all_hvparams, |
|
730 |
get_hv_fn=hypervisor.GetHypervisor): |
|
731 |
"""Verifies the hypervisor. Appends the results to the 'results' list. |
|
732 |
|
|
733 |
@type what: C{dict} |
|
734 |
@param what: a dictionary of things to check |
|
735 |
@type vm_capable: boolean |
|
736 |
@param vm_capable: whether or not this not is vm capable |
|
737 |
@type result: dict |
|
738 |
@param result: dictionary of verification results; results of the |
|
739 |
verifications in this function will be added here |
|
740 |
@type all_hvparams: dict of dict of string |
|
741 |
@param all_hvparams: dictionary mapping hypervisor names to hvparams |
|
742 |
@type get_hv_fn: function |
|
743 |
@param get_hv_fn: function to retrieve the hypervisor, to improve testability |
|
744 |
|
|
745 |
""" |
|
746 |
if not vm_capable: |
|
747 |
return |
|
748 |
|
|
749 |
if constants.NV_HYPERVISOR in what: |
|
750 |
result[constants.NV_HYPERVISOR] = {} |
|
751 |
for hv_name in what[constants.NV_HYPERVISOR]: |
|
752 |
hvparams = all_hvparams[hv_name] |
|
753 |
try: |
|
754 |
val = get_hv_fn(hv_name).Verify(hvparams=hvparams) |
|
755 |
except errors.HypervisorError, err: |
|
756 |
val = "Error while checking hypervisor: %s" % str(err) |
|
757 |
result[constants.NV_HYPERVISOR][hv_name] = val |
|
758 |
|
|
759 |
|
|
760 |
def _VerifyHvparams(what, vm_capable, result, |
|
761 |
get_hv_fn=hypervisor.GetHypervisor): |
|
762 |
"""Verifies the hvparams. Appends the results to the 'results' list. |
|
763 |
|
|
764 |
@type what: C{dict} |
|
765 |
@param what: a dictionary of things to check |
|
766 |
@type vm_capable: boolean |
|
767 |
@param vm_capable: whether or not this not is vm capable |
|
768 |
@type result: dict |
|
769 |
@param result: dictionary of verification results; results of the |
|
770 |
verifications in this function will be added here |
|
771 |
@type get_hv_fn: function |
|
772 |
@param get_hv_fn: function to retrieve the hypervisor, to improve testability |
|
773 |
|
|
774 |
""" |
|
775 |
if not vm_capable: |
|
776 |
return |
|
777 |
|
|
778 |
if constants.NV_HVPARAMS in what: |
|
779 |
result[constants.NV_HVPARAMS] = [] |
|
780 |
for source, hv_name, hvparms in what[constants.NV_HVPARAMS]: |
|
781 |
try: |
|
782 |
logging.info("Validating hv %s, %s", hv_name, hvparms) |
|
783 |
get_hv_fn(hv_name).ValidateParameters(hvparms) |
|
784 |
except errors.HypervisorError, err: |
|
785 |
result[constants.NV_HVPARAMS].append((source, hv_name, str(err))) |
|
786 |
|
|
787 |
|
|
729 | 788 |
def VerifyNode(what, cluster_name): |
730 | 789 |
"""Verify the status of the local node. |
731 | 790 |
|
... | ... | |
750 | 809 |
- node-net-test: list of nodes we should check node daemon port |
751 | 810 |
connectivity with |
752 | 811 |
- hypervisor: list with hypervisors to run the verify for |
812 |
|
|
753 | 813 |
@rtype: dict |
754 | 814 |
@return: a dictionary with the same keys as the input dict, and |
755 | 815 |
values representing the result of the checks |
... | ... | |
760 | 820 |
port = netutils.GetDaemonPort(constants.NODED) |
761 | 821 |
vm_capable = my_name not in what.get(constants.NV_VMNODES, []) |
762 | 822 |
|
763 |
if constants.NV_HYPERVISOR in what and vm_capable: |
|
764 |
result[constants.NV_HYPERVISOR] = tmp = {} |
|
765 |
for hv_name in what[constants.NV_HYPERVISOR]: |
|
766 |
try: |
|
767 |
val = hypervisor.GetHypervisor(hv_name).Verify() |
|
768 |
except errors.HypervisorError, err: |
|
769 |
val = "Error while checking hypervisor: %s" % str(err) |
|
770 |
tmp[hv_name] = val |
|
771 |
|
|
772 |
if constants.NV_HVPARAMS in what and vm_capable: |
|
773 |
result[constants.NV_HVPARAMS] = tmp = [] |
|
774 |
for source, hv_name, hvparms in what[constants.NV_HVPARAMS]: |
|
775 |
try: |
|
776 |
logging.info("Validating hv %s, %s", hv_name, hvparms) |
|
777 |
hypervisor.GetHypervisor(hv_name).ValidateParameters(hvparms) |
|
778 |
except errors.HypervisorError, err: |
|
779 |
tmp.append((source, hv_name, str(err))) |
|
823 |
_VerifyHypervisors(what, vm_capable, result, all_hvparams) |
|
824 |
_VerifyHvparams(what, vm_capable, result) |
|
780 | 825 |
|
781 | 826 |
if constants.NV_FILELIST in what: |
782 | 827 |
fingerprints = utils.FingerprintFiles(map(vcluster.LocalizeVirtualPath, |
b/lib/hypervisor/hv_base.py | ||
---|---|---|
263 | 263 |
|
264 | 264 |
return (cls.ANCILLARY_FILES, cls.ANCILLARY_FILES_OPT) |
265 | 265 |
|
266 |
def Verify(self): |
|
266 |
def Verify(self, hvparams=None):
|
|
267 | 267 |
"""Verify the hypervisor. |
268 | 268 |
|
269 |
@type hvparams: dict of strings |
|
270 |
@param hvparams: hypervisor parameters to be verified against |
|
271 |
|
|
269 | 272 |
@return: Problem description if something is wrong, C{None} otherwise |
270 | 273 |
|
271 | 274 |
""" |
b/lib/hypervisor/hv_chroot.py | ||
---|---|---|
276 | 276 |
user=constants.SSH_CONSOLE_USER, |
277 | 277 |
command=["chroot", root_dir]) |
278 | 278 |
|
279 |
def Verify(self): |
|
279 |
def Verify(self, hvparams=None):
|
|
280 | 280 |
"""Verify the hypervisor. |
281 | 281 |
|
282 | 282 |
For the chroot manager, it just checks the existence of the base dir. |
283 | 283 |
|
284 |
@type hvparams: dict of strings |
|
285 |
@param hvparams: hypervisor parameters to be verified against, not used |
|
286 |
in for chroot |
|
287 |
|
|
284 | 288 |
@return: Problem description if something is wrong, C{None} otherwise |
285 | 289 |
|
286 | 290 |
""" |
b/lib/hypervisor/hv_fake.py | ||
---|---|---|
233 | 233 |
message=("Console not available for fake" |
234 | 234 |
" hypervisor")) |
235 | 235 |
|
236 |
def Verify(self): |
|
236 |
def Verify(self, hvparams=None):
|
|
237 | 237 |
"""Verify the hypervisor. |
238 | 238 |
|
239 | 239 |
For the fake hypervisor, it just checks the existence of the base |
240 | 240 |
dir. |
241 | 241 |
|
242 |
@type hvparams: dict of strings |
|
243 |
@param hvparams: hypervisor parameters to be verified against; not used |
|
244 |
for fake hypervisors |
|
245 |
|
|
242 | 246 |
@return: Problem description if something is wrong, C{None} otherwise |
243 | 247 |
|
244 | 248 |
""" |
b/lib/hypervisor/hv_kvm.py | ||
---|---|---|
2044 | 2044 |
message=("No serial shell for instance %s" % |
2045 | 2045 |
instance.name)) |
2046 | 2046 |
|
2047 |
def Verify(self): |
|
2047 |
def Verify(self, hvparams=None):
|
|
2048 | 2048 |
"""Verify the hypervisor. |
2049 | 2049 |
|
2050 | 2050 |
Check that the required binaries exist. |
2051 | 2051 |
|
2052 |
@type hvparams: dict of strings |
|
2053 |
@param hvparams: hypervisor parameters to be verified against, not used here |
|
2054 |
|
|
2052 | 2055 |
@return: Problem description if something is wrong, C{None} otherwise |
2053 | 2056 |
|
2054 | 2057 |
""" |
b/lib/hypervisor/hv_lxc.py | ||
---|---|---|
417 | 417 |
user=constants.SSH_CONSOLE_USER, |
418 | 418 |
command=["lxc-console", "-n", instance.name]) |
419 | 419 |
|
420 |
def Verify(self): |
|
420 |
def Verify(self, hvparams=None):
|
|
421 | 421 |
"""Verify the hypervisor. |
422 | 422 |
|
423 | 423 |
For the LXC manager, it just checks the existence of the base dir. |
424 | 424 |
|
425 |
@type hvparams: dict of strings |
|
426 |
@param hvparams: hypervisor parameters to be verified against; not used here |
|
427 |
|
|
425 | 428 |
@return: Problem description if something is wrong, C{None} otherwise |
426 | 429 |
|
427 | 430 |
""" |
b/lib/hypervisor/hv_xen.py | ||
---|---|---|
630 | 630 |
command=[pathutils.XEN_CONSOLE_WRAPPER, |
631 | 631 |
constants.XEN_CMD, instance.name]) |
632 | 632 |
|
633 |
def Verify(self): |
|
633 |
def Verify(self, hvparams=None):
|
|
634 | 634 |
"""Verify the hypervisor. |
635 | 635 |
|
636 | 636 |
For Xen, this verifies that the xend process is running. |
637 | 637 |
|
638 |
@type hvparams: dict of strings |
|
639 |
@param hvparams: hypervisor parameters to be verified against |
|
640 |
|
|
638 | 641 |
@return: Problem description if something is wrong, C{None} otherwise |
639 | 642 |
|
640 | 643 |
""" |
641 |
result = self._RunXen(["info"]) |
|
644 |
if hvparams is None: |
|
645 |
return "Could not verify the hypervisor, because no hvparams were" \ |
|
646 |
" provided." |
|
647 |
|
|
648 |
if constants.HV_XEN_CMD in hvparams: |
|
649 |
xen_cmd = hvparams[constants.HV_XEN_CMD] |
|
650 |
try: |
|
651 |
self._CheckToolstack(xen_cmd) |
|
652 |
except errors.HypervisorError: |
|
653 |
return "The configured xen toolstack '%s' is not available on this" \ |
|
654 |
" node." % xen_cmd |
|
655 |
|
|
656 |
result = self._RunXen(["info"], hvparams=hvparams) |
|
642 | 657 |
if result.failed: |
643 |
return "'xm info' failed: %s, %s" % (result.fail_reason, result.output) |
|
658 |
return "Retrieving information from xen failed: %s, %s" % \ |
|
659 |
(result.fail_reason, result.output) |
|
644 | 660 |
|
645 | 661 |
return None |
646 | 662 |
|
... | ... | |
800 | 816 |
finally: |
801 | 817 |
utils.RunCmd([constants.XEN_CMD, "debug", "R"]) |
802 | 818 |
|
819 |
def _CheckToolstack(self, xen_cmd): |
|
820 |
"""Check whether the given toolstack is available on the node. |
|
821 |
|
|
822 |
@type xen_cmd: string |
|
823 |
@param xen_cmd: xen command (e.g. 'xm' or 'xl') |
|
824 |
|
|
825 |
""" |
|
826 |
binary_found = self._CheckToolstackBinary(xen_cmd) |
|
827 |
if not binary_found: |
|
828 |
raise errors.HypervisorError("No '%s' binary found on node." % xen_cmd) |
|
829 |
elif xen_cmd == constants.XEN_CMD_XL: |
|
830 |
if not self._CheckToolstackXlConfigured(): |
|
831 |
raise errors.HypervisorError("Toolstack '%s' is not enabled on this" |
|
832 |
"node." % xen_cmd) |
|
833 |
|
|
834 |
def _CheckToolstackBinary(self, xen_cmd): |
|
835 |
"""Checks whether the xen command's binary is found on the machine. |
|
836 |
|
|
837 |
""" |
|
838 |
if xen_cmd not in constants.KNOWN_XEN_COMMANDS: |
|
839 |
raise errors.HypervisorError("Unknown xen command '%s'." % xen_cmd) |
|
840 |
result = self._run_cmd_fn(["which", xen_cmd]) |
|
841 |
return not result.failed |
|
842 |
|
|
843 |
def _CheckToolstackXlConfigured(self): |
|
844 |
"""Checks whether xl is enabled on an xl-capable node. |
|
845 |
|
|
846 |
@rtype: bool |
|
847 |
@returns: C{True} if 'xl' is enabled, C{False} otherwise |
|
848 |
|
|
849 |
""" |
|
850 |
result = self._run_cmd_fn([constants.XEN_CMD_XL, "help"]) |
|
851 |
if not result.failed: |
|
852 |
return True |
|
853 |
elif result.failed: |
|
854 |
if "toolstack" in result.stderr: |
|
855 |
return False |
|
856 |
# xl fails for some other reason than the toolstack |
|
857 |
else: |
|
858 |
raise errors.HypervisorError("Cannot run xen ('%s'). Error: %s." |
|
859 |
% (constants.XEN_CMD_XL, result.stderr)) |
|
860 |
|
|
803 | 861 |
|
804 | 862 |
class XenPvmHypervisor(XenHypervisor): |
805 | 863 |
"""Xen PVM hypervisor interface""" |
b/lib/server/noded.py | ||
---|---|---|
738 | 738 |
"""Run a verify sequence on this node. |
739 | 739 |
|
740 | 740 |
""" |
741 |
return backend.VerifyNode(params[0], params[1]) |
|
741 |
(what, cluster_name) = params |
|
742 |
return backend.VerifyNode(what, cluster_name) |
|
742 | 743 |
|
743 | 744 |
@classmethod |
744 | 745 |
def perspective_node_verify_light(cls, params): |
b/test/py/ganeti.backend_unittest.py | ||
---|---|---|
77 | 77 |
|
78 | 78 |
|
79 | 79 |
class TestNodeVerify(testutils.GanetiTestCase): |
80 |
|
|
81 |
def setUp(self): |
|
82 |
testutils.GanetiTestCase.setUp(self) |
|
83 |
self._mock_hv = None |
|
84 |
|
|
85 |
def _GetHypervisor(self, hv_name): |
|
86 |
self._mock_hv = hypervisor.GetHypervisor(hv_name) |
|
87 |
self._mock_hv.ValidateParameters = mock.Mock() |
|
88 |
self._mock_hv.Verify = mock.Mock() |
|
89 |
return self._mock_hv |
|
90 |
|
|
80 | 91 |
def testMasterIPLocalhost(self): |
81 | 92 |
# this a real functional test, but requires localhost to be reachable |
82 | 93 |
local_data = (netutils.Hostname.GetSysName(), |
83 | 94 |
constants.IP4_ADDRESS_LOCALHOST) |
84 |
result = backend.VerifyNode({constants.NV_MASTERIP: local_data}, None) |
|
95 |
result = backend.VerifyNode({constants.NV_MASTERIP: local_data}, None, {})
|
|
85 | 96 |
self.failUnless(constants.NV_MASTERIP in result, |
86 | 97 |
"Master IP data not returned") |
87 | 98 |
self.failUnless(result[constants.NV_MASTERIP], "Cannot reach localhost") |
... | ... | |
92 | 103 |
bad_data = ("master.example.com", "192.0.2.1") |
93 | 104 |
# we just test that whatever TcpPing returns, VerifyNode returns too |
94 | 105 |
netutils.TcpPing = lambda a, b, source=None: False |
95 |
result = backend.VerifyNode({constants.NV_MASTERIP: bad_data}, None) |
|
106 |
result = backend.VerifyNode({constants.NV_MASTERIP: bad_data}, None, {})
|
|
96 | 107 |
self.failUnless(constants.NV_MASTERIP in result, |
97 | 108 |
"Master IP data not returned") |
98 | 109 |
self.failIf(result[constants.NV_MASTERIP], |
99 | 110 |
"Result from netutils.TcpPing corrupted") |
100 | 111 |
|
112 |
def testVerifyHvparams(self): |
|
113 |
test_hvparams = {constants.HV_XEN_CMD: constants.XEN_CMD_XL} |
|
114 |
test_what = {constants.NV_HVPARAMS: \ |
|
115 |
[("mynode", constants.HT_XEN_PVM, test_hvparams)]} |
|
116 |
result = {} |
|
117 |
backend._VerifyHvparams(test_what, True, result, |
|
118 |
get_hv_fn=self._GetHypervisor) |
|
119 |
self._mock_hv.ValidateParameters.assert_called_with(test_hvparams) |
|
120 |
|
|
121 |
def testVerifyHypervisors(self): |
|
122 |
hvname = constants.HT_XEN_PVM |
|
123 |
hvparams = {constants.HV_XEN_CMD: constants.XEN_CMD_XL} |
|
124 |
all_hvparams = {hvname: hvparams} |
|
125 |
test_what = {constants.NV_HYPERVISOR: [hvname]} |
|
126 |
result = {} |
|
127 |
backend._VerifyHypervisors( |
|
128 |
test_what, True, result, all_hvparams=all_hvparams, |
|
129 |
get_hv_fn=self._GetHypervisor) |
|
130 |
self._mock_hv.Verify.assert_called_with(hvparams=hvparams) |
|
131 |
|
|
101 | 132 |
|
102 | 133 |
def _DefRestrictedCmdOwner(): |
103 | 134 |
return (os.getuid(), os.getgid()) |
b/test/py/ganeti.hypervisor.hv_xen_unittest.py | ||
---|---|---|
412 | 412 |
mock_run_cmd.assert_called_with([expected_xen_cmd, self.XEN_LIST]) |
413 | 413 |
|
414 | 414 |
|
415 |
class TestXenHypervisorCheckToolstack(unittest.TestCase): |
|
416 |
|
|
417 |
def setUp(self): |
|
418 |
self.tmpdir = tempfile.mkdtemp() |
|
419 |
self.cfg_name = "xen_config" |
|
420 |
self.cfg_path = utils.PathJoin(self.tmpdir, self.cfg_name) |
|
421 |
self.hv = hv_xen.XenHypervisor() |
|
422 |
|
|
423 |
def tearDown(self): |
|
424 |
shutil.rmtree(self.tmpdir) |
|
425 |
|
|
426 |
def testBinaryNotFound(self): |
|
427 |
RESULT_FAILED = utils.RunResult(1, None, "", "", "", None, None) |
|
428 |
mock_run_cmd = mock.Mock(return_value=RESULT_FAILED) |
|
429 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
430 |
_run_cmd_fn=mock_run_cmd) |
|
431 |
result = hv._CheckToolstackBinary("xl") |
|
432 |
self.assertFalse(result) |
|
433 |
|
|
434 |
def testCheckToolstackXlConfigured(self): |
|
435 |
RESULT_OK = utils.RunResult(0, None, "", "", "", None, None) |
|
436 |
mock_run_cmd = mock.Mock(return_value=RESULT_OK) |
|
437 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
438 |
_run_cmd_fn=mock_run_cmd) |
|
439 |
result = hv._CheckToolstackXlConfigured() |
|
440 |
self.assertTrue(result) |
|
441 |
|
|
442 |
def testCheckToolstackXlNotConfigured(self): |
|
443 |
RESULT_FAILED = utils.RunResult( |
|
444 |
1, None, "", |
|
445 |
"ERROR: A different toolstack (xm) have been selected!", |
|
446 |
"", None, None) |
|
447 |
mock_run_cmd = mock.Mock(return_value=RESULT_FAILED) |
|
448 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
449 |
_run_cmd_fn=mock_run_cmd) |
|
450 |
result = hv._CheckToolstackXlConfigured() |
|
451 |
self.assertFalse(result) |
|
452 |
|
|
453 |
def testCheckToolstackXlFails(self): |
|
454 |
RESULT_FAILED = utils.RunResult( |
|
455 |
1, None, "", |
|
456 |
"ERROR: The pink bunny hid the binary.", |
|
457 |
"", None, None) |
|
458 |
mock_run_cmd = mock.Mock(return_value=RESULT_FAILED) |
|
459 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
460 |
_run_cmd_fn=mock_run_cmd) |
|
461 |
self.assertRaises(errors.HypervisorError, hv._CheckToolstackXlConfigured) |
|
462 |
|
|
463 |
|
|
415 | 464 |
class TestXenHypervisorWriteConfigFile(unittest.TestCase): |
416 | 465 |
def setUp(self): |
417 | 466 |
self.tmpdir = tempfile.mkdtemp() |
... | ... | |
436 | 485 |
self.fail("Exception was not raised") |
437 | 486 |
|
438 | 487 |
|
488 |
class TestXenHypervisorVerify(unittest.TestCase): |
|
489 |
|
|
490 |
def setUp(self): |
|
491 |
output = testutils.ReadTestData("xen-xm-info-4.0.1.txt") |
|
492 |
self._result_ok = utils.RunResult(0, None, output, "", "", None, None) |
|
493 |
|
|
494 |
def testVerify(self): |
|
495 |
hvparams = {constants.HV_XEN_CMD : constants.XEN_CMD_XL} |
|
496 |
mock_run_cmd = mock.Mock(return_value=self._result_ok) |
|
497 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
498 |
_run_cmd_fn=mock_run_cmd) |
|
499 |
hv._CheckToolstack = mock.Mock(return_value=True) |
|
500 |
result = hv.Verify(hvparams) |
|
501 |
self.assertTrue(result is None) |
|
502 |
|
|
503 |
def testVerifyToolstackNotOk(self): |
|
504 |
hvparams = {constants.HV_XEN_CMD : constants.XEN_CMD_XL} |
|
505 |
mock_run_cmd = mock.Mock(return_value=self._result_ok) |
|
506 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
507 |
_run_cmd_fn=mock_run_cmd) |
|
508 |
hv._CheckToolstack = mock.Mock() |
|
509 |
hv._CheckToolstack.side_effect = errors.HypervisorError("foo") |
|
510 |
result = hv.Verify(hvparams) |
|
511 |
self.assertTrue(result is not None) |
|
512 |
|
|
513 |
def testVerifyFailing(self): |
|
514 |
result_failed = utils.RunResult(1, None, "", "", "", None, None) |
|
515 |
mock_run_cmd = mock.Mock(return_value=result_failed) |
|
516 |
hv = hv_xen.XenHypervisor(_cfgdir=NotImplemented, |
|
517 |
_run_cmd_fn=mock_run_cmd) |
|
518 |
hv._CheckToolstack = mock.Mock(return_value=True) |
|
519 |
result = hv.Verify() |
|
520 |
self.assertTrue(result is not None) |
|
521 |
|
|
522 |
|
|
439 | 523 |
class _TestXenHypervisor(object): |
440 | 524 |
TARGET = NotImplemented |
441 | 525 |
CMD = NotImplemented |
... | ... | |
565 | 649 |
"testinstance.example.com", |
566 | 650 |
]) |
567 | 651 |
|
568 |
def testVerify(self): |
|
569 |
output = testutils.ReadTestData("xen-xm-info-4.0.1.txt") |
|
570 |
hv = self._GetHv(run_cmd=compat.partial(self._SuccessCommand, |
|
571 |
output)) |
|
572 |
self.assertTrue(hv.Verify() is None) |
|
573 |
|
|
574 |
def testVerifyFailing(self): |
|
575 |
hv = self._GetHv(run_cmd=self._FailingCommand) |
|
576 |
self.assertTrue("failed:" in hv.Verify()) |
|
577 |
|
|
578 | 652 |
def _StartInstanceCommand(self, inst, paused, failcreate, cmd): |
579 | 653 |
if cmd == [self.CMD, "info"]: |
580 | 654 |
output = testutils.ReadTestData("xen-xm-info-4.0.1.txt") |
Also available in: Unified diff