Revision 6a855aaa htools/Ganeti/HTools/QC.hs
b/htools/Ganeti/HTools/QC.hs | ||
---|---|---|
1060 | 1060 |
IntMap.size il' == length ixes && |
1061 | 1061 |
length ixes == length cstats |
1062 | 1062 |
|
1063 |
-- | Checks that on a 4-8 node cluster, once we allocate an instance, |
|
1064 |
-- we can also evacuate it. |
|
1065 |
prop_ClusterAllocEvac inst = |
|
1066 |
forAll (choose (4, 8)) $ \count -> |
|
1067 |
forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node -> |
|
1068 |
let (nl, il, inst') = makeSmallEmptyCluster node count inst |
|
1063 |
-- | Helper function to create a cluster with the given range of nodes |
|
1064 |
-- and allocate an instance on it. |
|
1065 |
genClusterAlloc count node inst = |
|
1066 |
let nl = makeSmallCluster node count |
|
1069 | 1067 |
in case Cluster.genAllocNodes defGroupList nl 2 True >>= |
1070 |
Cluster.tryAlloc nl il inst' of
|
|
1071 |
Types.Bad _ -> False
|
|
1068 |
Cluster.tryAlloc nl Container.empty inst of
|
|
1069 |
Types.Bad _ -> Types.Bad "Can't allocate"
|
|
1072 | 1070 |
Types.Ok as -> |
1073 | 1071 |
case Cluster.asSolution as of |
1074 |
Nothing -> False
|
|
1072 |
Nothing -> Types.Bad "Empty solution?"
|
|
1075 | 1073 |
Just (xnl, xi, _, _) -> |
1076 |
let sdx = Instance.sNode xi |
|
1077 |
il' = Container.add (Instance.idx xi) xi il |
|
1078 |
in case IAlloc.processRelocate defGroupList xnl il' |
|
1079 |
(Instance.idx xi) 1 [sdx] of |
|
1080 |
Types.Ok _ -> True |
|
1081 |
_ -> False |
|
1074 |
let xil = Container.add (Instance.idx xi) xi Container.empty |
|
1075 |
in Types.Ok (xnl, xil, xi) |
|
1076 |
|
|
1077 |
-- | Checks that on a 4-8 node cluster, once we allocate an instance, |
|
1078 |
-- we can also relocate it. |
|
1079 |
prop_ClusterAllocRelocate = |
|
1080 |
forAll (choose (4, 8)) $ \count -> |
|
1081 |
forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node -> |
|
1082 |
forAll (arbitrary `suchThat` (isInstanceSmallerThanNode node)) $ \inst -> |
|
1083 |
case genClusterAlloc count node inst of |
|
1084 |
Types.Bad msg -> failTest msg |
|
1085 |
Types.Ok (nl, il, inst') -> |
|
1086 |
case IAlloc.processRelocate defGroupList nl il |
|
1087 |
(Instance.idx inst) 1 [Instance.sNode inst'] of |
|
1088 |
Types.Ok _ -> printTestCase "??" True -- huh, how to make |
|
1089 |
-- this nicer... |
|
1090 |
Types.Bad msg -> failTest $ "Failed to relocate: " ++ msg |
|
1091 |
|
|
1092 |
-- | Helper property checker for the result of a nodeEvac or |
|
1093 |
-- changeGroup operation. |
|
1094 |
check_EvacMode grp inst result = |
|
1095 |
case result of |
|
1096 |
Types.Bad msg -> failTest $ "Couldn't evacuate/change group:" ++ msg |
|
1097 |
Types.Ok (_, _, es) -> |
|
1098 |
let moved = Cluster.esMoved es |
|
1099 |
failed = Cluster.esFailed es |
|
1100 |
opcodes = not . null $ Cluster.esOpCodes es |
|
1101 |
in failmsg ("'failed' not empty: " ++ show failed) (null failed) .&&. |
|
1102 |
failmsg "'opcodes' is null" opcodes .&&. |
|
1103 |
case moved of |
|
1104 |
[(idx', gdx, _)] -> failmsg "invalid instance moved" (idx == idx') |
|
1105 |
.&&. |
|
1106 |
failmsg "wrong target group" |
|
1107 |
(gdx == Group.idx grp) |
|
1108 |
v -> failmsg ("invalid solution: " ++ show v) False |
|
1109 |
where failmsg = \msg -> printTestCase ("Failed to evacuate: " ++ msg) |
|
1110 |
idx = Instance.idx inst |
|
1111 |
|
|
1112 |
-- | Checks that on a 4-8 node cluster, once we allocate an instance, |
|
1113 |
-- we can also node-evacuate it. |
|
1114 |
prop_ClusterAllocEvacuate = |
|
1115 |
forAll (choose (4, 8)) $ \count -> |
|
1116 |
forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node -> |
|
1117 |
forAll (arbitrary `suchThat` (isInstanceSmallerThanNode node)) $ \inst -> |
|
1118 |
case genClusterAlloc count node inst of |
|
1119 |
Types.Bad msg -> failTest msg |
|
1120 |
Types.Ok (nl, il, inst') -> |
|
1121 |
conjoin $ map (\mode -> check_EvacMode defGroup inst' $ |
|
1122 |
Cluster.tryNodeEvac defGroupList nl il mode |
|
1123 |
[Instance.idx inst']) [minBound..maxBound] |
|
1124 |
|
|
1125 |
-- | Checks that on a 4-8 node cluster with two node groups, once we |
|
1126 |
-- allocate an instance on the first node group, we can also change |
|
1127 |
-- its group. |
|
1128 |
prop_ClusterAllocChangeGroup = |
|
1129 |
forAll (choose (4, 8)) $ \count -> |
|
1130 |
forAll (genOnlineNode `suchThat` (isNodeBig 4)) $ \node -> |
|
1131 |
forAll (arbitrary `suchThat` (isInstanceSmallerThanNode node)) $ \inst -> |
|
1132 |
case genClusterAlloc count node inst of |
|
1133 |
Types.Bad msg -> failTest msg |
|
1134 |
Types.Ok (nl, il, inst') -> |
|
1135 |
-- we need to add a second node group and nodes to the cluster |
|
1136 |
let nl2 = Container.elems $ makeSmallCluster node count |
|
1137 |
grp2 = Group.setIdx defGroup (Group.idx defGroup + 1) |
|
1138 |
maxndx = maximum . map Node.idx $ nl2 |
|
1139 |
nl3 = map (\n -> n { Node.group = Group.idx grp2 |
|
1140 |
, Node.idx = Node.idx n + maxndx }) nl2 |
|
1141 |
nl4 = Container.fromList . map (\n -> (Node.idx n, n)) $ nl3 |
|
1142 |
gl' = Container.add (Group.idx grp2) grp2 defGroupList |
|
1143 |
nl' = IntMap.union nl nl4 |
|
1144 |
in check_EvacMode grp2 inst' $ |
|
1145 |
Cluster.tryChangeGroup gl' nl' il [] [Instance.idx inst'] |
|
1082 | 1146 |
|
1083 | 1147 |
-- | Check that allocating multiple instances on a cluster, then |
1084 | 1148 |
-- adding an empty node, results in a valid rebalance. |
... | ... | |
1161 | 1225 |
, 'prop_CStats_sane |
1162 | 1226 |
, 'prop_ClusterAlloc_sane |
1163 | 1227 |
, 'prop_ClusterCanTieredAlloc |
1164 |
, 'prop_ClusterAllocEvac |
|
1228 |
, 'prop_ClusterAllocRelocate |
|
1229 |
, 'prop_ClusterAllocEvacuate |
|
1230 |
, 'prop_ClusterAllocChangeGroup |
|
1165 | 1231 |
, 'prop_ClusterAllocBalance |
1166 | 1232 |
, 'prop_ClusterCheckConsistency |
1167 | 1233 |
, 'prop_ClusterSplitCluster |
Also available in: Unified diff