diff --git a/Ganeti/HTools/Cluster.hs b/Ganeti/HTools/Cluster.hs index 91ef098fa52bda53e4ffe000deb204dbd23b1f6f..ab21b3240bed628bd8802e59686db5eb11a6cf86 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 57d485996230ea71cd02baf03cb7976d067343d2..05f8ba1445967b8586f542ae5fb114dd4a6036db 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 2cf8aae2c558209a0d3684a761ad3eee2d7a4215..1c51f386a75f77710fdb0e6e48ddb8eea5d17c00 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