From 10ef6b4ec1c213b95ab197136ecb5a406129bea6 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Wed, 15 Dec 2010 18:18:47 +0100 Subject: [PATCH] Change the Node.group attribute Currently, the Node.group attribute is the UUID of the group, as until recently Ganeti didn't export the node group properties. Since it does so now, we make the following changes (again apologies for a big patch): - we change the group attribute to be an index, similar to the way an Instance.pnode and snode attributes point to the parent node(s) - on load, we read the group.uuid attribute and we use that to lookup the actual group index, from previously-loaded groups info - this means that we now first read groups, then read nodes using the group info, and then read instances using the node info This patch leaves a few functions showing the group index (ugly since it's htools internal), will be converted later. Signed-off-by: Iustin Pop <iustin@google.com> Reviewed-by: Balazs Lecz <leczb@google.com> --- Ganeti/HTools/Cluster.hs | 30 +++++++++++++++--------------- Ganeti/HTools/IAlloc.hs | 15 +++++++++------ Ganeti/HTools/Luxi.hs | 22 +++++++++++----------- Ganeti/HTools/Node.hs | 9 ++++----- Ganeti/HTools/QC.hs | 26 ++++++++++++++++++++------ Ganeti/HTools/Rapi.hs | 16 ++++++++-------- Ganeti/HTools/Simu.hs | 2 +- Ganeti/HTools/Text.hs | 35 +++++++++++++++++------------------ hbal.hs | 29 ++++++++++++++++++++--------- hscan.hs | 2 +- hspace.hs | 6 +++--- 11 files changed, 109 insertions(+), 83 deletions(-) diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index 7d11ddb0a..66d87526b 100644 --- a/Ganeti/HTools/Cluster.hs +++ b/Ganeti/HTools/Cluster.hs @@ -625,16 +625,16 @@ tryAlloc _ _ _ reqn = fail $ "Unsupported number of allocation \ "), only two supported" -- | Given a group/result, describe it as a nice (list of) messages -solutionDescription :: (GroupID, Result AllocSolution) -> [String] +solutionDescription :: (Gdx, Result AllocSolution) -> [String] solutionDescription (groupId, result) = case result of - Ok solution -> map (printf "Group %s: %s" groupId) (asLog solution) - Bad message -> [printf "Group %s: error %s" groupId message] + Ok solution -> map (printf "Group %d: %s" groupId) (asLog solution) + Bad message -> [printf "Group %d: error %s" groupId message] -- | From a list of possibly bad and possibly empty solutions, filter -- only the groups with a valid result -filterMGResults :: [(GroupID, Result AllocSolution)] -> - [(GroupID, AllocSolution)] +filterMGResults :: [(Gdx, Result AllocSolution)] -> + [(Gdx, AllocSolution)] filterMGResults = filter (not . null . asSolutions . snd) . map (\(y, Ok x) -> (y, x)) . @@ -651,7 +651,7 @@ tryMGAlloc mgnl mgil inst cnt = -- TODO: currently we consider all groups preferred sols = map (\(gid, (nl, il)) -> (gid, tryAlloc nl il inst cnt)) groups:: - [(GroupID, Result AllocSolution)] + [(Gdx, Result AllocSolution)] all_msgs = concatMap solutionDescription sols goodSols = filterMGResults sols extractScore = \(_, _, _, x) -> x @@ -660,7 +660,7 @@ tryMGAlloc mgnl mgil inst cnt = in if null sortedSols then Bad $ intercalate ", " all_msgs else let (final_group, final_sol) = head sortedSols - selmsg = "Selected group: " ++ final_group + selmsg = "Selected group: " ++ show final_group in Ok $ final_sol { asLog = selmsg:all_msgs } -- | Try to relocate an instance on the cluster. @@ -925,19 +925,19 @@ iMoveToJob nl il idx move = FailoverAndReplace ns -> [ opF, opR ns ] -- | Computes the group of an instance -instanceGroup :: Node.List -> Instance.Instance -> Result GroupID +instanceGroup :: Node.List -> Instance.Instance -> Result Gdx instanceGroup nl i = let sidx = Instance.sNode i pnode = Container.find (Instance.pNode i) nl snode = if sidx == Node.noSecondary then pnode else Container.find sidx nl - puuid = Node.group pnode - suuid = Node.group snode - in if puuid /= suuid - then fail ("Instance placed accross two node groups, primary " ++ puuid ++ - ", secondary " ++ suuid) - else return puuid + pgroup = Node.group pnode + sgroup = Node.group snode + in if pgroup /= sgroup + then fail ("Instance placed accross two node groups, primary " ++ + show pgroup ++ ", secondary " ++ show sgroup) + else return pgroup -- | Compute the list of badly allocated instances (split across node -- groups) @@ -947,7 +947,7 @@ findSplitInstances nl il = -- | Splits a cluster into the component node groups splitCluster :: Node.List -> Instance.List -> - [(GroupID, (Node.List, Instance.List))] + [(Gdx, (Node.List, Instance.List))] splitCluster nl il = let ngroups = Node.computeGroups (Container.elems nl) in map (\(guuid, nodes) -> diff --git a/Ganeti/HTools/IAlloc.hs b/Ganeti/HTools/IAlloc.hs index 4117fd478..f015f9d42 100644 --- a/Ganeti/HTools/IAlloc.hs +++ b/Ganeti/HTools/IAlloc.hs @@ -75,15 +75,17 @@ parseInstance ktn n a = do return (n, Instance.setBoth (snd base) pidx sidx) -- | Parses a node as found in the cluster node list. -parseNode :: String -- ^ The node's name +parseNode :: NameAssoc -- ^ The group association + -> String -- ^ The node's name -> [(String, JSValue)] -- ^ The JSON object -> Result (String, Node.Node) -parseNode n a = do +parseNode ktg n a = do offline <- fromObj "offline" a drained <- fromObj "drained" a guuid <- fromObj "group" a + gidx <- lookupGroup ktg n guuid node <- (if offline || drained - then return $ Node.create n 0 0 0 0 0 0 True guuid + then return $ Node.create n 0 0 0 0 0 0 True gidx else do mtotal <- fromObj "total_memory" a mnode <- fromObj "reserved_memory" a @@ -92,7 +94,7 @@ parseNode n a = do dfree <- fromObj "free_disk" a ctotal <- fromObj "total_cpus" a return $ Node.create n mtotal mnode mfree - dtotal dfree ctotal False guuid) + dtotal dfree ctotal False gidx) return (n, node) -- | Parses a group as found in the cluster group list. @@ -114,10 +116,11 @@ parseData body = do -- existing group parsing glist <- liftM fromJSObject (fromObj "nodegroups" obj) gobj <- mapM (\(x, y) -> asJSObject y >>= parseGroup x . fromJSObject) glist - let (_, gl) = assignIndices gobj + let (ktg, gl) = assignIndices gobj -- existing node parsing nlist <- liftM fromJSObject (fromObj "nodes" obj) - nobj <- mapM (\(x,y) -> asJSObject y >>= parseNode x . fromJSObject) nlist + nobj <- mapM (\(x,y) -> + asJSObject y >>= parseNode ktg x . fromJSObject) nlist let (ktn, nl) = assignIndices nobj -- existing instance parsing ilist <- fromObj "instances" obj diff --git a/Ganeti/HTools/Luxi.hs b/Ganeti/HTools/Luxi.hs index c5b93437c..88c22849d 100644 --- a/Ganeti/HTools/Luxi.hs +++ b/Ganeti/HTools/Luxi.hs @@ -120,22 +120,22 @@ parseInstance ktn (JSArray [ name, disk, mem, vcpus parseInstance _ v = fail ("Invalid instance query result: " ++ show v) -- | Parse a node list in JSON format. -getNodes :: JSValue -> Result [(String, Node.Node)] -getNodes arr = toArray arr >>= mapM parseNode +getNodes :: NameAssoc -> JSValue -> Result [(String, Node.Node)] +getNodes ktg arr = toArray arr >>= mapM (parseNode ktg) -- | Construct a node from a JSON object. -parseNode :: JSValue -> Result (String, Node.Node) -parseNode (JSArray [ name, mtotal, mnode, mfree, dtotal, dfree - , ctotal, offline, drained, vm_capable, g_uuid ]) +parseNode :: NameAssoc -> JSValue -> Result (String, Node.Node) +parseNode ktg (JSArray [ name, mtotal, mnode, mfree, dtotal, dfree + , ctotal, offline, drained, vm_capable, g_uuid ]) = do xname <- annotateResult "Parsing new node" (fromJVal name) let convert v = annotateResult ("Node '" ++ xname ++ "'") (fromJVal v) xoffline <- convert offline xdrained <- convert drained xvm_capable <- convert vm_capable - xguuid <- convert g_uuid + xgdx <- convert g_uuid >>= lookupGroup ktg xname node <- (if xoffline || xdrained || not xvm_capable - then return $ Node.create xname 0 0 0 0 0 0 True xguuid + then return $ Node.create xname 0 0 0 0 0 0 True xgdx else do xmtotal <- convert mtotal xmnode <- convert mnode @@ -144,10 +144,10 @@ parseNode (JSArray [ name, mtotal, mnode, mfree, dtotal, dfree xdfree <- convert dfree xctotal <- convert ctotal return $ Node.create xname xmtotal xmnode xmfree - xdtotal xdfree xctotal False xguuid) + xdtotal xdfree xctotal False xgdx) return (xname, node) -parseNode v = fail ("Invalid node query result: " ++ show v) +parseNode _ v = fail ("Invalid node query result: " ++ show v) getClusterTags :: JSValue -> Result [String] getClusterTags v = do @@ -188,8 +188,8 @@ parseData :: (Result JSValue, Result JSValue, Result JSValue, Result JSValue) -> Result (Group.List, Node.List, Instance.List, [String]) parseData (groups, nodes, instances, cinfo) = do group_data <- groups >>= getGroups - let (_, group_idx) = assignIndices group_data - node_data <- nodes >>= getNodes + let (group_names, group_idx) = assignIndices group_data + node_data <- nodes >>= getNodes group_names let (node_names, node_idx) = assignIndices node_data inst_data <- instances >>= getInstances node_names let (_, inst_idx) = assignIndices inst_data diff --git a/Ganeti/HTools/Node.hs b/Ganeti/HTools/Node.hs index 5fd331d7b..73162e6ea 100644 --- a/Ganeti/HTools/Node.hs +++ b/Ganeti/HTools/Node.hs @@ -121,7 +121,7 @@ data Node = Node , utilPool :: T.DynUtil -- ^ Total utilisation capacity , utilLoad :: T.DynUtil -- ^ Sum of instance utilisation , pTags :: TagMap -- ^ Map of primary instance tags and their count - , group :: T.GroupID -- ^ The node's group (as UUID) + , group :: T.Gdx -- ^ The node's group (index) } deriving (Show, Eq) instance T.Element Node where @@ -185,7 +185,7 @@ conflictingPrimaries (Node { pTags = t }) = Foldable.sum t - Map.size t -- The index and the peers maps are empty, and will be need to be -- update later via the 'setIdx' and 'buildPeers' functions. create :: String -> Double -> Int -> Int -> Double - -> Int -> Double -> Bool -> String -> Node + -> Int -> Double -> Bool -> T.Gdx -> Node create name_init mem_t_init mem_n_init mem_f_init dsk_t_init dsk_f_init cpu_t_init offline_init group_init = Node { name = name_init @@ -487,7 +487,6 @@ showField t field = "ptags" -> intercalate "," . map (\(k, v) -> printf "%s=%d" k v) . Map.toList $ pTags t "peermap" -> show $ peers t - "group.uuid" -> group t _ -> T.unknownField where T.DynUtil { T.cpuWeight = uC, T.memWeight = uM, @@ -526,7 +525,7 @@ showHeader field = "nload" -> ("lNet", True) "ptags" -> ("PrimaryTags", False) "peermap" -> ("PeerMap", False) - "group.uuid" -> ("GroupUUID", False) + -- TODO: add node fields (group.uuid, group) _ -> (T.unknownField, False) -- | String converter for the node list functionality. @@ -543,7 +542,7 @@ defaultFields = -- | Split a list of nodes into a list of (node group UUID, list of -- associated nodes) -computeGroups :: [Node] -> [(T.GroupID, [Node])] +computeGroups :: [Node] -> [(T.Gdx, [Node])] computeGroups nodes = let nodes' = sortBy (comparing group) nodes nodes'' = groupBy (\a b -> group a == group b) nodes' diff --git a/Ganeti/HTools/QC.hs b/Ganeti/HTools/QC.hs index bf83fcc41..536d1bf2d 100644 --- a/Ganeti/HTools/QC.hs +++ b/Ganeti/HTools/QC.hs @@ -56,6 +56,7 @@ import qualified Ganeti.HTools.Instance as Instance import qualified Ganeti.HTools.Loader as Loader import qualified Ganeti.HTools.Luxi import qualified Ganeti.HTools.Node as Node +import qualified Ganeti.HTools.Group as Group import qualified Ganeti.HTools.PeerMap as PeerMap import qualified Ganeti.HTools.Rapi import qualified Ganeti.HTools.Simu @@ -78,6 +79,17 @@ maxDsk = 1024 * 1024 * 8 maxCpu :: Int maxCpu = 1024 +defGroup :: Group.Group +defGroup = flip Group.setIdx 0 $ + Group.create "default" Utils.defaultGroupID + Types.AllocPreferred + +defGroupList :: Group.List +defGroupList = Container.fromAssocList [(Group.idx defGroup, defGroup)] + +defGroupAssoc :: Data.Map.Map String Types.Gdx +defGroupAssoc = Data.Map.singleton (Group.uuid defGroup) (Group.idx defGroup) + -- * Helper functions -- | Simple checker for whether OpResult is fail or pass @@ -187,7 +199,7 @@ instance Arbitrary Node.Node where offl <- arbitrary let n = Node.create name (fromIntegral mem_t) mem_n mem_f (fromIntegral dsk_t) dsk_f (fromIntegral cpu_t) offl - Utils.defaultGroupID + 0 n' = Node.buildPeers n Container.empty return n' @@ -483,7 +495,9 @@ prop_Text_Load_Node name tm nm fm td fd tc fo = then "Y" else "N" any_broken = any (< 0) [tm, nm, fm, td, fd, tc] - in case Text.loadNode [name, tm_s, nm_s, fm_s, td_s, fd_s, tc_s, fo_s] of + gid = Group.uuid defGroup + in case Text.loadNode defGroupAssoc + [name, tm_s, nm_s, fm_s, td_s, fd_s, tc_s, fo_s, gid] of Nothing -> False Just (name', node) -> if fo || any_broken @@ -498,11 +512,11 @@ prop_Text_Load_Node name tm nm fm td fd tc fo = Node.tCpu node == fromIntegral tc prop_Text_Load_NodeFail fields = - length fields /= 8 ==> isNothing $ Text.loadNode fields + length fields /= 8 ==> isNothing $ Text.loadNode Data.Map.empty fields prop_Text_NodeLSIdempotent node = - (Text.loadNode . - Utils.sepSplit '|' . Text.serializeNode) n == + (Text.loadNode defGroupAssoc. + Utils.sepSplit '|' . Text.serializeNode defGroupList) n == Just (Node.name n, n) -- override failN1 to what loadNode returns by default where n = node { Node.failN1 = True, Node.offline = False } @@ -750,7 +764,7 @@ prop_ClusterAllocBalance node = prop_ClusterCheckConsistency node inst = let nl = makeSmallCluster node 3 [node1, node2, node3] = Container.elems nl - node3' = node3 { Node.group = "other-uuid" } + node3' = node3 { Node.group = 1 } nl' = Container.add (Node.idx node3') node3' nl inst1 = Instance.setBoth inst (Node.idx node1) (Node.idx node2) inst2 = Instance.setBoth inst (Node.idx node1) Node.noSecondary diff --git a/Ganeti/HTools/Rapi.hs b/Ganeti/HTools/Rapi.hs index 5b6b3f295..1d33214b5 100644 --- a/Ganeti/HTools/Rapi.hs +++ b/Ganeti/HTools/Rapi.hs @@ -71,9 +71,9 @@ getInstances ktn body = mapM (parseInstance ktn . fromJSObject) -- | Parse a node list in JSON format. -getNodes :: String -> Result [(String, Node.Node)] -getNodes body = loadJSArray "Parsing node data" body >>= - mapM (parseNode . fromJSObject) +getNodes :: NameAssoc -> String -> Result [(String, Node.Node)] +getNodes ktg body = loadJSArray "Parsing node data" body >>= + mapM (parseNode ktg . fromJSObject) -- | Parse a group list in JSON format. getGroups :: String -> Result [(String, Group.Group)] @@ -105,13 +105,13 @@ parseInstance ktn a = do return (name, inst) -- | Construct a node from a JSON object. -parseNode :: [(String, JSValue)] -> Result (String, Node.Node) -parseNode a = do +parseNode :: NameAssoc -> [(String, JSValue)] -> Result (String, Node.Node) +parseNode ktg a = do name <- tryFromObj "Parsing new node" a "name" let extract s = tryFromObj ("Node '" ++ name ++ "'") a s offline <- extract "offline" drained <- extract "drained" - guuid <- extract "group.uuid" + guuid <- extract "group.uuid" >>= lookupGroup ktg name node <- (if offline || drained then return $ Node.create name 0 0 0 0 0 0 True guuid else do @@ -149,8 +149,8 @@ parseData :: (Result String, Result String, Result String, Result String) -> Result (Group.List, Node.List, Instance.List, [String]) parseData (group_body, node_body, inst_body, tags_body) = do group_data <- group_body >>= getGroups - let (_, group_idx) = assignIndices group_data - node_data <- node_body >>= getNodes + let (group_names, group_idx) = assignIndices group_data + node_data <- node_body >>= getNodes group_names let (node_names, node_idx) = assignIndices node_data inst_data <- inst_body >>= getInstances node_names let (_, inst_idx) = assignIndices inst_data diff --git a/Ganeti/HTools/Simu.hs b/Ganeti/HTools/Simu.hs index 503394e22..f2a71d9a3 100644 --- a/Ganeti/HTools/Simu.hs +++ b/Ganeti/HTools/Simu.hs @@ -62,7 +62,7 @@ parseData ndata = do let n = Node.create (printf "node%03d" idx) (fromIntegral mem) 0 mem (fromIntegral disk) disk - (fromIntegral cpu) False defaultGroupID + (fromIntegral cpu) False 0 in (idx, Node.setIdx n idx) ) [1..cnt] return (Container.fromAssocList [(0, Group.setIdx defgroup 0)], diff --git a/Ganeti/HTools/Text.hs b/Ganeti/HTools/Text.hs index e49e30a5d..2b2c725ff 100644 --- a/Ganeti/HTools/Text.hs +++ b/Ganeti/HTools/Text.hs @@ -52,17 +52,18 @@ import qualified Ganeti.HTools.Node as Node import qualified Ganeti.HTools.Instance as Instance -- | Serialize a single node -serializeNode :: Node.Node -> String -serializeNode node = +serializeNode :: Group.List -> Node.Node -> String +serializeNode gl node = printf "%s|%.0f|%d|%d|%.0f|%d|%.0f|%c|%s" (Node.name node) (Node.tMem node) (Node.nMem node) (Node.fMem node) (Node.tDsk node) (Node.fDsk node) (Node.tCpu node) (if Node.offline node then 'Y' else 'N') - (Node.group node) + (Group.uuid grp) + where grp = Container.find (Node.group node) gl -- | Generate node file data from node objects -serializeNodes :: Node.List -> String -serializeNodes = unlines . map serializeNode . Container.elems +serializeNodes :: Group.List -> Node.List -> String +serializeNodes gl = unlines . map (serializeNode gl) . Container.elems -- | Serialize a single instance serializeInstance :: Node.List -> Instance.Instance -> String @@ -86,9 +87,9 @@ serializeInstances nl = unlines . map (serializeInstance nl) . Container.elems -- | Generate complete cluster data from node and instance lists -serializeCluster :: Node.List -> Instance.List -> String -serializeCluster nl il = - let ndata = serializeNodes nl +serializeCluster :: Group.List -> Node.List -> Instance.List -> String +serializeCluster gl nl il = + let ndata = serializeNodes gl nl idata = serializeInstances nl il in ndata ++ ['\n'] ++ idata @@ -100,14 +101,12 @@ loadGroup [name, gid] = loadGroup s = fail $ "Invalid/incomplete group data: '" ++ show s ++ "'" -- | Load a node from a field list. -loadNode :: (Monad m) => [String] -> m (String, Node.Node) --- compatibility wrapper for old text files -loadNode [name, tm, nm, fm, td, fd, tc, fo] = - loadNode [name, tm, nm, fm, td, fd, tc, fo, defaultGroupID] -loadNode [name, tm, nm, fm, td, fd, tc, fo, gu] = do +loadNode :: (Monad m) => NameAssoc -> [String] -> m (String, Node.Node) +loadNode ktg [name, tm, nm, fm, td, fd, tc, fo, gu] = do + gdx <- lookupGroup ktg name gu new_node <- if any (== "?") [tm,nm,fm,td,fd,tc] || fo == "Y" then - return $ Node.create name 0 0 0 0 0 0 True gu + return $ Node.create name 0 0 0 0 0 0 True gdx else do vtm <- tryRead name tm vnm <- tryRead name nm @@ -115,9 +114,9 @@ loadNode [name, tm, nm, fm, td, fd, tc, fo, gu] = do vtd <- tryRead name td vfd <- tryRead name fd vtc <- tryRead name tc - return $ Node.create name vtm vnm vfm vtd vfd vtc False gu + return $ Node.create name vtm vnm vfm vtd vfd vtc False gdx return (name, new_node) -loadNode s = fail $ "Invalid/incomplete node data: '" ++ show s ++ "'" +loadNode _ s = fail $ "Invalid/incomplete node data: '" ++ show s ++ "'" -- | Load an instance from a field list. loadInst :: (Monad m) => @@ -168,9 +167,9 @@ parseData fdata = do [] -> Bad "Invalid format of the input file (no instance data)" _:xs -> Ok xs {- group file: name uuid -} - (_, gl) <- loadTabular glines loadGroup + (ktg, gl) <- loadTabular glines loadGroup {- node file: name t_mem n_mem f_mem t_disk f_disk -} - (ktn, nl) <- loadTabular nfixed loadNode + (ktn, nl) <- loadTabular nfixed (loadNode ktg) {- instance file: name mem disk status pnode snode -} (_, il) <- loadTabular ifixed (loadInst ktn) return (gl, nl, il, []) diff --git a/hbal.hs b/hbal.hs index 68a391f4c..47ad6b112 100644 --- a/hbal.hs +++ b/hbal.hs @@ -41,6 +41,7 @@ import Text.Printf (printf, hPrintf) import qualified Ganeti.HTools.Container as Container import qualified Ganeti.HTools.Cluster as Cluster +import qualified Ganeti.HTools.Group as Group import qualified Ganeti.HTools.Node as Node import qualified Ganeti.HTools.Instance as Instance @@ -226,7 +227,7 @@ main = do verbose = optVerbose opts shownodes = optShowNodes opts - (_, fixed_nl, ilf, ctags) <- loadExternalData opts + (gl, fixed_nl, ilf, ctags) <- loadExternalData opts let offline_names = optOffline opts all_nodes = Container.elems fixed_nl @@ -270,7 +271,7 @@ main = do let ngroups = Cluster.splitCluster nlf ilf when (length ngroups > 1 && isNothing (optGroup opts)) $ do hPutStrLn stderr "Found multiple node groups:" - mapM_ (hPutStrLn stderr . (" " ++) . fst ) ngroups + mapM_ (hPutStrLn stderr . (" " ++) . show . fst ) ngroups hPutStrLn stderr "Aborting." exitWith $ ExitFailure 1 @@ -278,22 +279,32 @@ main = do (Container.size nlf) (Container.size ilf) - (guuid, (nl, il)) <- case optGroup opts of - Nothing -> return $ head ngroups - Just g -> case lookup g ngroups of + (gname, (nl, il)) <- case optGroup opts of + Nothing -> do + let (gidx, cdata) = head ngroups + grp = Container.find gidx gl + return (Group.name grp, cdata) + Just g -> case Container.findByName gl g of Nothing -> do hPutStrLn stderr $ "Node group " ++ g ++ " not found. Node group list is:" - mapM_ (hPutStrLn stderr . (" " ++) . fst ) ngroups + mapM_ (hPutStrLn stderr . (" " ++) . Group.name ) (Container.elems gl) hPutStrLn stderr "Aborting." exitWith $ ExitFailure 1 - Just cdata -> return (g, cdata) + Just grp -> + case lookup (Group.idx grp) ngroups of + Nothing -> do + -- TODO: while this is unlikely to happen, log here the + -- actual group data to help debugging + hPutStrLn stderr $ "Internal failure, missing group idx" + exitWith $ ExitFailure 1 + Just cdata -> return (Group.name grp, cdata) unless oneline $ printf "Group size %d nodes, %d instances\n" (Container.size nl) (Container.size il) - putStrLn $ "Selected node group: " ++ guuid + putStrLn $ "Selected node group: " ++ gname when (length csf > 0 && not oneline && verbose > 1) $ printf "Note: Stripping common suffix of '%s' from names\n" csf @@ -379,7 +390,7 @@ main = do when (isJust $ optSaveCluster opts) $ do let out_path = fromJust $ optSaveCluster opts - adata = serializeCluster fin_nl fin_il + adata = serializeCluster gl fin_nl fin_il writeFile out_path adata printf "The cluster state has been written to file '%s'\n" out_path diff --git a/hscan.hs b/hscan.hs index 9e1877760..5c8dbda90 100644 --- a/hscan.hs +++ b/hscan.hs @@ -95,7 +95,7 @@ processData :: Result (Group.List, Node.List, Instance.List, [String]) processData input_data = do (gl, nl, il, _) <- input_data >>= Loader.mergeData [] [] [] let (_, fix_nl) = Loader.checkData nl il - adata = serializeCluster nl il + adata = serializeCluster gl nl il return (gl, fix_nl, il, adata) -- | Writes cluster data out diff --git a/hspace.hs b/hspace.hs index 189b0ba98..103a63088 100644 --- a/hspace.hs +++ b/hspace.hs @@ -207,7 +207,7 @@ main = do ispec = optISpec opts shownodes = optShowNodes opts - (_, fixed_nl, il, _) <- loadExternalData opts + (gl, fixed_nl, il, _) <- loadExternalData opts printKeys $ map (\(a, fn) -> ("SPEC_" ++ a, fn ispec)) specData printKeys [ ("SPEC_RQN", printf "%d" (optINodes opts)) ] @@ -312,7 +312,7 @@ main = do when (isJust $ optSaveCluster opts) $ do let out_path = (fromJust $ optSaveCluster opts) <.> "tiered" - adata = serializeCluster trl_nl trl_il + adata = serializeCluster gl trl_nl trl_il writeFile out_path adata hPrintf stderr "The cluster state after tiered allocation\ \ has been written to file '%s'\n" @@ -346,7 +346,7 @@ main = do when (isJust $ optSaveCluster opts) $ do let out_path = (fromJust $ optSaveCluster opts) <.> "alloc" - adata = serializeCluster fin_nl fin_il + adata = serializeCluster gl fin_nl fin_il writeFile out_path adata hPrintf stderr "The cluster state after standard allocation\ \ has been written to file '%s'\n" -- GitLab