From c5f7412edc6fbf4b1de51b21112f94698576ee26 Mon Sep 17 00:00:00 2001 From: Iustin Pop <iustin@google.com> Date: Sun, 18 Oct 2009 17:44:13 +0100 Subject: [PATCH] Generalise the node/instance listing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch introduces a generic formatTable function (based on, and similar to the Ganeti one, but different and more FP in style) and changes the node and instance listing to it. The node list (due to the many variables) is still a little bit hackish unfortunately⦠--- Ganeti/HTools/Cluster.hs | 41 +++++++++++------------- Ganeti/HTools/Node.hs | 67 +++++++++++++++++++++++----------------- Ganeti/HTools/Utils.hs | 20 ++++++++++++ 3 files changed, 76 insertions(+), 52 deletions(-) diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index 91ef098fa..ab21b3240 100644 --- a/Ganeti/HTools/Cluster.hs +++ b/Ganeti/HTools/Cluster.hs @@ -687,34 +687,29 @@ printSolution nl il sol = printNodes :: Node.List -> String printNodes nl = let snl = sortBy (compare `on` Node.idx) (Container.elems nl) - m_name = maximum . map (length . Node.name) $ snl - helper = Node.list m_name - h2 = printf " %5s %5s %5s %5s" "lCpu" "lMem" "lDsk" "lNet"::String - header = printf - "%2s %-*s %5s %5s %5s %5s %5s %5s %5s %5s %4s %4s \ - \%3s %3s %6s %6s %5s" - " F" m_name "Name" - "t_mem" "n_mem" "i_mem" "x_mem" "f_mem" "r_mem" - "t_dsk" "f_dsk" "pcpu" "vcpu" - "pri" "sec" "p_fmem" "p_fdsk" "r_cpu"::String - in unlines ((header++h2):map helper snl) + header = ["F", "Name" + , "t_mem", "n_mem", "i_mem", "x_mem", "f_mem", "r_mem" + , "t_dsk", "f_dsk", "pcpu", "vcpu", "pri", "sec" + , "p_fmem", "p_fdsk", "r_cpu" + , "lCpu", "lMem", "lDsk", "lNet" ] + isnum = False:False:repeat True + in unlines . map ((:) ' ' . intercalate " ") $ + formatTable (header:map Node.list snl) isnum -- | Print the instance list. printInsts :: Node.List -> Instance.List -> String printInsts nl il = let sil = sortBy (compare `on` Instance.idx) (Container.elems il) - m_name = maximum . map (length . Instance.name) $ sil - m_nnm = maximum . map (length . Node.name) $ Container.elems nl - helper inst = printf "%2s %-*s %-*s %-*s" - " " m_name (Instance.name inst) - m_nnm (Container.nameOf nl (Instance.pNode inst)) - m_nnm (let sdx = Instance.sNode inst - in if sdx == Node.noSecondary - then "" - else Container.nameOf nl sdx) - header = printf "%2s %-*s %-*s %-*s" - " " m_name "Name" m_nnm "Pri_node" m_nnm "Sec_node"::String - in unlines (header:map helper sil) + helper inst = [ (Instance.name inst) + , (Container.nameOf nl (Instance.pNode inst)) + , (let sdx = Instance.sNode inst + in if sdx == Node.noSecondary + then "" + else Container.nameOf nl sdx) ] + header = ["Name", "Pri_node", "Sec_node"] + isnum = repeat False + in unlines . map ((:) ' ' . intercalate " ") $ + formatTable (header:map helper sil) isnum -- | Shows statistics for a given node list. printStats :: Node.List -> String diff --git a/Ganeti/HTools/Node.hs b/Ganeti/HTools/Node.hs index 57d485996..05f8ba144 100644 --- a/Ganeti/HTools/Node.hs +++ b/Ganeti/HTools/Node.hs @@ -346,33 +346,42 @@ availDisk t = -- * Display functions +showField :: Node -> String -> String +showField t field = + case field of + "name" -> name t + "status" -> if offline t then "-" + else if failN1 t then "*" else " " + "tmem" -> printf "%5.0f" $ tMem t + "nmem" -> printf "%5d" $ nMem t + "xmem" -> printf "%5d" $ xMem t + "fmem" -> printf "%5d" $ fMem t + "imem" -> printf "%5d" imem + "rmem" -> printf "%5d" $ rMem t + "tdsk" -> printf "%5.0f" $ tDsk t / 1024 + "fdsk" -> printf "%5d" $ fDsk t `div` 1024 + "tcpu" -> printf "%4.0f" $ tCpu t + "ucpu" -> printf "%4d" $ uCpu t + "plist" -> printf "%3d" $ length (pList t) + "slist" -> printf "%3d" $ length (sList t) + "pfmem" -> printf "%6.4f" $ pMem t + "pfdsk" -> printf "%6.4f" $ pDsk t + "rcpu" -> printf "%5.2f" $ pCpu t + "cload" -> printf "%5.3f" uC + "mload" -> printf "%5.3f" uM + "dload" -> printf "%5.3f" uD + "nload" -> printf "%5.3f" uN + _ -> printf "<unknown field>" + where + T.DynUtil { T.cpuWeight = uC, T.memWeight = uM, + T.dskWeight = uD, T.netWeight = uN } = utilLoad t + imem = truncate (tMem t) - nMem t - xMem t - fMem t + + -- | String converter for the node list functionality. -list :: Int -> Node -> String -list mname t = - let pl = length $ pList t - sl = length $ sList t - mp = pMem t - dp = pDsk t - cp = pCpu t - off = offline t - fn = failN1 t - tmem = tMem t - nmem = nMem t - xmem = xMem t - fmem = fMem t - imem = truncate tmem - nmem - xmem - fmem - T.DynUtil { T.cpuWeight = uC, T.memWeight = uM, - T.dskWeight = uD, T.netWeight = uN } = utilLoad t - wstr = printf " %5.3f %5.3f %5.3f %5.3f" uC uM uD uN::String - in - if off - then printf " - %-*s %57s %3d %3d" - mname (name t) "" pl sl - else - printf " %c %-*s %5.0f %5d %5d %5d %5d %5d %5.0f %5d\ - \ %4.0f %4d %3d %3d %6.4f %6.4f %5.2f" - (if off then '-' else if fn then '*' else ' ') - mname (name t) tmem nmem imem xmem fmem (rMem t) - (tDsk t / 1024) (fDsk t `div` 1024) - (tCpu t) (uCpu t) - pl sl mp dp cp ++ wstr +list :: Node -> [String] +list t = map (showField t) + [ "status", "name", "tmem", "nmem", "imem", "xmem", "fmem" + , "rmem", "tdsk", "fdsk", "tcpu", "ucpu", "plist", "slist" + , "pfmem", "pfdsk", "rcpu" + , "cload", "mload", "dload", "nload" ] diff --git a/Ganeti/HTools/Utils.hs b/Ganeti/HTools/Utils.hs index 2cf8aae2c..1c51f386a 100644 --- a/Ganeti/HTools/Utils.hs +++ b/Ganeti/HTools/Utils.hs @@ -35,6 +35,7 @@ module Ganeti.HTools.Utils , asObjectList , fromJResult , tryRead + , formatTable ) where import Data.List @@ -140,3 +141,22 @@ parseChoices name s _ = fail $ name ++ ": cannot parse string '" ++ s ++ "'" -- | Safe 'read' function returning data encapsulated in a Result. tryRead :: (Monad m, Read a) => String -> String -> m a tryRead name s = parseChoices name s $ reads s + +-- | Format a table of strings to maintain consistent length +formatTable :: [[String]] -> [Bool] -> [[String]] +formatTable vals numpos = + let vtrans = transpose vals -- transpose, so that we work on rows + -- rather than columns + mlens = map (maximum . map length) vtrans + expnd = map (\(flds, isnum, ml) -> + map (\val -> + let delta = ml - length val + filler = replicate delta ' ' + in if delta > 0 + then if isnum + then filler ++ val + else val ++ filler + else val + ) flds + ) (zip3 vtrans numpos mlens) + in transpose expnd -- GitLab