LGTM, thanks On Fri, Mar 20, 2015 at 3:32 PM, 'Petr Pudlak' via ganeti-devel < [email protected]> wrote:
> commit 94d312e52635bed7daac9e86a77873eb2e114e5e > Merge: 2d2f44d d54e169 > Author: Petr Pudlak <[email protected]> > Date: Fri Mar 20 15:29:33 2015 +0100 > > Merge branch 'stable-2.12' into stable-2.13 > > * stable-2.12 > QA: Fix CheckFileUnmodified to work with vcluster > QA: Fix white-spaces in CheckFileUnmodified > QA: Check that the cluster verify doesn't change the config > QA: Allow to check that an operation doesn't change a file > Use only shared configuration lock for ComputeDRBDMap > Only assert properties of non-None objects > If any IO error happens during job forking, retry > Add a function for retrying `MonadError` computations > > * stable-2.11 > Improve speed of Xen hypervisor unit tests > Improve Xen instance state handling > > * stable-2.10 > Make QA fail if KVM hotplugging fails > Always preserve QA command output > Don't lose stdout/stderr in AssertCommand > qa_utils: Allow passing fail=None to AssertCommand > qa_utils: Make AssertCommand return stdout/stderr as well > Allow plain/DRBD conversions regardless of lack of disks > Add support for ipolicy modifications to mock config > > Conflicts: > lib/cmdlib/instance.py - propagate changes from 2.12 > qa/qa_cluster.py - propagate changes from 2.12 > qa/qa_instance.py - propagate changes from 2.12 > qa/qa_utils.py - propagate changes from 2.12 > src/Ganeti/Utils/Monad.hs - merge changes from both branches > > diff --cc lib/cmdlib/instance.py > index bed2e3d,d5b2c6b..269e47f > --- a/lib/cmdlib/instance.py > +++ b/lib/cmdlib/instance.py > @@@ -3916,11 -3679,18 +3916,16 @@@ class LUInstanceSetParams(LogicalUnit) > > """ > secondary_nodes = > self.cfg.GetInstanceSecondaryNodes(self.instance.uuid) > - assert len(secondary_nodes) == 1 > + > assert self.instance.disk_template == constants.DT_DRBD8 > + assert len(secondary_nodes) == 1 or not self.instance.disks > + > - pnode_uuid = self.instance.primary_node > - > + # it will not be possible to calculate the snode_uuid later > + snode_uuid = None > + if secondary_nodes: > + snode_uuid = secondary_nodes[0] > > - snode_uuid = secondary_nodes[0] > - feedback_fn("Converting template to plain") > + feedback_fn("Converting disk template from 'drbd' to 'plain'") > > disks = self.cfg.GetInstanceDisks(self.instance.uuid) > old_disks = AnnotateDiskParams(self.instance, disks, self.cfg) > diff --cc qa/qa_cluster.py > index 51a3b15,adf508a..166a5ee > --- a/qa/qa_cluster.py > +++ b/qa/qa_cluster.py > @@@ -51,8 -51,8 +51,8 @@@ import qa_job_util > import qa_logging > import qa_utils > > -from qa_utils import AssertEqual, AssertCommand, GetCommandOutput, \ > - CheckFileUnmodified > +from qa_utils import AssertEqual, AssertCommand, > AssertRedirectedCommand, \ > - GetCommandOutput > ++ GetCommandOutput, CheckFileUnmodified > > > # Prefix for LVM volumes created by QA code during tests > diff --cc qa/qa_instance.py > index ffe6a31,6cbe96e..a00cfa7 > --- a/qa/qa_instance.py > +++ b/qa/qa_instance.py > @@@ -633,22 -630,7 +652,14 @@@ def TestInstanceModify(instance) > ]) > elif default_hv == constants.HT_KVM and \ > qa_config.TestEnabled("instance-device-hotplug"): > - args.extend([ > - ["--net", "-1:add", "--hotplug"], > - ["--net", "-1:modify,mac=aa:bb:cc:dd:ee:ff", "--hotplug", > "--force"], > - ["--net", "-1:remove", "--hotplug"], > - ]) > - args.extend([ > - ["--disk", "-1:add,size=1G", "--hotplug"], > - ["--disk", "-1:remove", "--hotplug"], > - ]) > + _TestKVMHotplug(instance) > + elif default_hv == constants.HT_LXC: > + args.extend([ > + ["-H", "%s=0" % constants.HV_CPU_MASK], > + ["-H", "%s=%s" % (constants.HV_CPU_MASK, constants.VALUE_DEFAULT)], > + ["-H", "%s=0" % constants.HV_LXC_NUM_TTYS], > + ["-H", "%s=%s" % (constants.HV_LXC_NUM_TTYS, > constants.VALUE_DEFAULT)], > + ]) > > url = "http://example.com/busybox.img" > args.extend([ > diff --cc src/Ganeti/Utils/Monad.hs > index c1bd630,0000000..cd09a0d > mode 100644,000000..100644 > --- a/src/Ganeti/Utils/Monad.hs > +++ b/src/Ganeti/Utils/Monad.hs > @@@ -1,87 -1,0 +1,97 @@@ > +{-| Utility functions for MonadPlus operations > + > +-} > + > +{- > + > +Copyright (C) 2014 Google Inc. > +All rights reserved. > + > +Redistribution and use in source and binary forms, with or without > +modification, are permitted provided that the following conditions are > +met: > + > +1. Redistributions of source code must retain the above copyright notice, > +this list of conditions and the following disclaimer. > + > +2. Redistributions in binary form must reproduce the above copyright > +notice, this list of conditions and the following disclaimer in the > +documentation and/or other materials provided with the distribution. > + > +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS > +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED > +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A > PARTICULAR > +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, > +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, > +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR > +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF > +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING > +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS > +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. > + > +-} > + > +module Ganeti.Utils.Monad > + ( mretryN > + , retryMaybeN > + , anyM > + , allM > + , orM > + , unfoldrM > + , unfoldrM' > ++ , retryErrorN > + ) where > + > +import Control.Monad > ++import Control.Monad.Error > +import Control.Monad.Trans.Maybe > + > +-- | Retries the given action up to @n@ times. > +-- The action signals failure by 'mzero'. > +mretryN :: (MonadPlus m) => Int -> (Int -> m a) -> m a > +mretryN n = msum . flip map [1..n] > + > +-- | Retries the given action up to @n@ times. > +-- The action signals failure by 'mzero'. > +retryMaybeN :: (Monad m) => Int -> (Int -> MaybeT m a) -> m (Maybe a) > +retryMaybeN = (runMaybeT .) . mretryN > + > ++-- | Retries the given action up to @n@ times until it succeeds. > ++-- If all actions fail, the error of the last one is returned. > ++-- The action is always run at least once, even if @n@ is less than 1. > ++retryErrorN :: (MonadError e m) => Int -> (Int -> m a) -> m a > ++retryErrorN n f = loop 1 > ++ where > ++ loop i | i < n = catchError (f i) (const $ loop (i + 1)) > ++ | otherwise = f i > + > - -- From monad-loops (until we can / want to depend on it): > ++-- * From monad-loops (until we can / want to depend on it): > + > +-- | Short-circuit 'any' with a monadic predicate. > +anyM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool > +anyM p = foldM (\v x -> if v then return True else p x) False > + > +-- | Short-circuit 'all' with a monadic predicate. > +allM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool > +allM p = foldM (\v x -> if v then p x else return False) True > + > +-- | Short-circuit 'or' for values of type Monad m => m Bool > +orM :: (Monad m) => [m Bool] -> m Bool > +orM = anyM id > + > +-- |See 'Data.List.unfoldr'. This is a monad-friendly version of that. > +unfoldrM :: (Monad m) => (a -> m (Maybe (b,a))) -> a -> m [b] > +unfoldrM = unfoldrM' > + > +-- | See 'Data.List.unfoldr'. This is a monad-friendly version of that, > with a > +-- twist. Rather than returning a list, it returns any MonadPlus type of > your > +-- choice. > +unfoldrM' :: (Monad m, MonadPlus f) => (a -> m (Maybe (b,a))) -> a -> m > (f b) > +unfoldrM' f z = do > + x <- f z > + case x of > + Nothing -> return mzero > + Just (x', z') -> do > + xs <- unfoldrM' f z' > + return (return x' `mplus` xs) > Hrvoje Ribicic Ganeti Engineering Google Germany GmbH Dienerstr. 12, 80331, München Registergericht und -nummer: Hamburg, HRB 86891 Sitz der Gesellschaft: Hamburg Geschäftsführer: Graham Law, Christine Elizabeth Flores Steuernummer: 48/725/00206 Umsatzsteueridentifikationsnummer: DE813741370
