diff --git a/NEWS b/NEWS index 8768e192e400bb7609513f30c3534dd15ece2c81..a34d1983229f55ec0331e461f764d9366f24dbcf 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,45 @@ News ==== +Version 2.5.1 +------------- + +*(Released Fri, 11 May 2012)* + +A small bugfix release. + +The main issues solved are on the topic of compatibility with newer LVM +releases: + +- fixed parsing of ``lv_attr`` field +- adapted to new ``vgreduce --removemissing`` behaviour where sometimes + the ``--force`` flag is needed + +Also on the topic of compatibility, ``tools/lvmstrap`` has been changed +to accept kernel 3.x too (was hardcoded to 2.6.*). + +A regression present in 2.5.0 that broke handling (in the gnt-* scripts) +of hook results and that also made display of other errors suboptimal +was fixed; the code behaves now like 2.4 and earlier. + +Another change in 2.5, the cleanup of the OS scripts environment, is too +aggressive: it removed even the ``PATH`` variable, which requires the OS +scripts to *always* need to export it. Since this is a bit too strict, +we now export a minimal PATH, the same that we export for hooks. + +The fix for issue 201 (Preserve bridge MTU in KVM ifup script) was +integrated into this release. + +Finally, a few other miscellaneous changes were done (no new features, +just small improvements): + +- Fix ``gnt-group --help`` display +- Fix hardcoded Xen kernel path +- Fix grow-disk handling of invalid units +- Update synopsis for ``gnt-cluster repair-disk-sizes`` +- Accept both PUT and POST in noded (makes future upgrade to 2.6 easier) + + Version 2.5.0 ------------- diff --git a/configure.ac b/configure.ac index 12d5aa094ce9ca5abda5214013271abc7862654d..a2d67b6fd051512ab90e3ea44cbbf059bf67c9c6 100644 --- a/configure.ac +++ b/configure.ac @@ -1,7 +1,7 @@ # Configure script for Ganeti m4_define([gnt_version_major], [2]) m4_define([gnt_version_minor], [5]) -m4_define([gnt_version_revision], [0]) +m4_define([gnt_version_revision], [1]) m4_define([gnt_version_suffix], []) m4_define([gnt_version_full], m4_format([%d.%d.%d%s], diff --git a/doc/install.rst b/doc/install.rst index d899abda427b7d03bd17d8d5538b6318391aed16..54a76ab9861b5d400171a5a13a8ae35b45ed6664 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -341,6 +341,26 @@ outside of ganeti. The vif scripts will only add /32 routes to your instances, through their interface, in the table you specified (under KVM, and in the main table under Xen). +.. admonition:: Bridging issues with certain kernels + + Some kernel versions (e.g. 2.6.32) have an issue where the bridge + will automatically change its ``MAC`` address to the lower-numbered + slave on port addition and removal. This means that, depending on + the ``MAC`` address of the actual NIC on the node and the addresses + of the instances, it could be that starting, stopping or migrating + instances will lead to timeouts due to the address of the bridge + (and thus node itself) changing. + + To prevent this, it's enough to set the bridge manually to a + specific ``MAC`` address, which will disable this automatic address + change. In Debian, this can be done as follows in the bridge + configuration snippet:: + + up ip link set addr $(cat /sys/class/net/$IFACE/address) dev $IFACE + + which will "set" the bridge address to the initial one, disallowing + changes. + .. admonition:: Bridging under Debian The recommended way to configure the Xen bridge is to edit your @@ -357,6 +377,8 @@ KVM, and in the main table under Xen). bridge_ports eth0 bridge_stp off bridge_fd 0 + # example for setting manually the bridge address to the eth0 NIC + up ip link set addr $(cat /sys/class/net/eth0/address) dev $IFACE The following commands need to be executed on the local console: diff --git a/lib/backend.py b/lib/backend.py index 2fa571364f70c19a700f9d30e22f08071a83efb7..40ce7e7348bb4e01e43ae4065f155a5147d44c59 100644 --- a/lib/backend.py +++ b/lib/backend.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -78,7 +78,7 @@ _IES_PID_FILE = "pid" _IES_CA_FILE = "ca" #: Valid LVS output line regex -_LVSLINE_REGEX = re.compile("^ *([^|]+)\|([^|]+)\|([0-9.]+)\|([^|]{6})\|?$") +_LVSLINE_REGEX = re.compile("^ *([^|]+)\|([^|]+)\|([0-9.]+)\|([^|]{6,})\|?$") class RPCFail(Exception): @@ -2253,6 +2253,11 @@ def OSCoreEnv(os_name, inst_os, os_params, debug=0): for pname, pvalue in os_params.items(): result["OSP_%s" % pname.upper()] = pvalue + # Set a default path otherwise programs called by OS scripts (or + # even hooks called from OS scripts) might break, and we don't want + # to have each script require setting a PATH variable + result["PATH"] = constants.HOOKS_PATH + return result diff --git a/lib/client/gnt_group.py b/lib/client/gnt_group.py index 199b9276d57d381a983cf13efbf3dfc4292531ff..903f569e4ba4c38029e65146bba564c801a3464e 100644 --- a/lib/client/gnt_group.py +++ b/lib/client/gnt_group.py @@ -244,15 +244,15 @@ commands = { "Evacuate all instances within a group"), "list-tags": ( ListTags, ARGS_ONE_GROUP, [], - "<instance_name>", "List the tags of the given instance"), + "<group_name>", "List the tags of the given group"), "add-tags": ( AddTags, [ArgGroup(min=1, max=1), ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT], - "<instance_name> tag...", "Add tags to the given instance"), + "<group_name> tag...", "Add tags to the given group"), "remove-tags": ( RemoveTags, [ArgGroup(min=1, max=1), ArgUnknown()], [TAG_SRC_OPT, PRIORITY_OPT, SUBMIT_OPT], - "<instance_name> tag...", "Remove tags from given instance"), + "<group_name> tag...", "Remove tags from the given group"), } diff --git a/lib/client/gnt_instance.py b/lib/client/gnt_instance.py index 5ecf16f0839e35836f2de444a981eae065d98b58..9d9d7eca6528108c107dedee722cb8ee1dc58c71 100644 --- a/lib/client/gnt_instance.py +++ b/lib/client/gnt_instance.py @@ -640,7 +640,11 @@ def GrowDisk(opts, args): except (TypeError, ValueError), err: raise errors.OpPrereqError("Invalid disk index: %s" % str(err), errors.ECODE_INVAL) - amount = utils.ParseUnit(args[2]) + try: + amount = utils.ParseUnit(args[2]) + except errors.UnitParseError: + raise errors.OpPrereqError("Can't parse the given amount '%s'" % args[2], + errors.ECODE_INVAL) op = opcodes.OpInstanceGrowDisk(instance_name=instance, disk=disk, amount=amount, wait_for_sync=opts.wait_for_sync) diff --git a/lib/constants.py b/lib/constants.py index f401781955dc61783e82a233cd642d3286a4c41a..884759f968efae889ea61d9ae7c9cb4aea10753a 100644 --- a/lib/constants.py +++ b/lib/constants.py @@ -1324,7 +1324,7 @@ HVC_DEFAULTS = { HV_USE_BOOTLOADER: False, HV_BOOTLOADER_PATH: XEN_BOOTLOADER, HV_BOOTLOADER_ARGS: "", - HV_KERNEL_PATH: "/boot/vmlinuz-2.6-xenU", + HV_KERNEL_PATH: XEN_KERNEL, HV_INITRD_PATH: "", HV_ROOT_PATH: "/dev/sda1", HV_KERNEL_ARGS: "ro", diff --git a/lib/errors.py b/lib/errors.py index 7319cd9f13c7fb03661050424d761c102b943004..91c862aa9551fb6bf755fb5a04ebdc4dac15f71a 100644 --- a/lib/errors.py +++ b/lib/errors.py @@ -1,7 +1,7 @@ # # -# Copyright (C) 2006, 2007, 2008, 2009, 2010 Google Inc. +# Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -488,4 +488,5 @@ def MaybeRaise(result): error = GetEncodedError(result) if error: (errcls, args) = error - raise errcls(args) + # pylint: disable=W0142 + raise errcls(*args) diff --git a/test/ganeti.errors_unittest.py b/test/ganeti.errors_unittest.py index ec25912c60da75ed8a74396c14a4d6fbd0f52fc8..f10f661c7ae0b03822da571311d079947a101f07 100755 --- a/test/ganeti.errors_unittest.py +++ b/test/ganeti.errors_unittest.py @@ -1,7 +1,7 @@ #!/usr/bin/python # -# Copyright (C) 2010 Google Inc. +# Copyright (C) 2010, 2012 Google Inc. # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -53,14 +53,25 @@ class TestErrors(testutils.GanetiTestCase): ("GenericError", (True, 100, "foo", ["x", "y"]))) def testMaybeRaise(self): + testvals = [None, 1, 2, 3, "Hello World", (1, ), (1, 2, 3), + ("NoErrorClassName", []), ("NoErrorClassName", None), + ("GenericError", [1, 2, 3], None), ("GenericError", 1)] # These shouldn't raise - for i in [None, 1, 2, 3, "Hello World", (1, ), (1, 2, 3), - ("NoErrorClassName", []), ("NoErrorClassName", None), - ("GenericError", [1, 2, 3], None), ("GenericError", 1)]: + for i in testvals: errors.MaybeRaise(i) self.assertRaises(errors.GenericError, errors.MaybeRaise, ("GenericError", ["Hello"])) + # Check error encoding + for i in testvals: + src = errors.GenericError(i) + try: + errors.MaybeRaise(errors.EncodeException(src)) + except errors.GenericError, dst: + self.assertEqual(src.args, dst.args) + self.assertEqual(src.__class__, dst.__class__) + else: + self.fail("Exception %s not raised" % repr(src)) def testGetEncodedError(self): self.assertEqualValues(errors.GetEncodedError(["GenericError", diff --git a/tools/lvmstrap b/tools/lvmstrap index eb87cd2325b919d3c0c8f7a02be0048803bb53b9..3d1affd312f85ea164e6d1dca9f5bf010ecc2fd4 100755 --- a/tools/lvmstrap +++ b/tools/lvmstrap @@ -272,9 +272,9 @@ def CheckPrereq(): raise PrereqError("This tool only runs on Linux" " (detected OS: %s)." % osname) - if not release.startswith("2.6."): + if not (release.startswith("2.6.") or release.startswith("3.")): raise PrereqError("Wrong major kernel version (detected %s, needs" - " 2.6.*)" % release) + " 2.6.* or 3.*)" % release) if not os.path.ismount("/sys"): raise PrereqError("Can't find a filesystem mounted at /sys."