<commit_before>{-| Cluster checker.

-}

{-

Copyright (C) 2012 Google Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU Gene52al Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

-}

module Ganeti.HTools.Program.Hcheck (main, options) where

import Control.Monad
import List (transpose)
import System.Exit
import System.IO
import Text.Printf (printf)

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

import qualified Ganeti.HTools.Program.Hbal as Hbal

import Ganeti.HTools.CLI
import Ganeti.HTools.ExtLoader
import Ganeti.HTools.Loader
import Ganeti.HTools.Types

-- | Options list and functions.
options :: [OptType]
options =
  [ oDataFile
  , oDiskMoves
  , oDynuFile
  , oEvacMode
  , oExInst
  , oExTags
  , oIAllocSrc
  , oInstMoves
  , oLuxiSocket
  , oMachineReadable
  , oMaxCpu
  , oMaxSolLength
  , oMinDisk
  , oMinGain
  , oMinGainLim
  , oMinScore
  , oNoSimulation
  , oOfflineNode
  , oQuiet
  , oRapiMaster
  , oSelInst
  , oShowHelp
  , oShowVer
  , oVerbose
  ]

-- | Check phase - are we before (initial) or after rebalance.
data Phase = Initial
           | Rebalanced

-- | Level of presented statistics.
data Level = GroupLvl
           | ClusterLvl

-- | Prefix for machine readable names
htcPrefix :: String
htcPrefix = "HCHECK"

-- | Phase-specific prefix for machine readable version.
phasePrefix :: Phase -> String
phasePrefix Initial = "INIT"
phasePrefix Rebalanced = "FINAL"

-- | Description of phases for human readable version.
phaseDescription :: Phase -> String
phaseDescription Initial = "initially"
phaseDescription Rebalanced = "after rebalancing"

-- | Level-specific prefix for machine readable version.
levelPrefix :: Level -> String
levelPrefix GroupLvl = "GROUP"
levelPrefix ClusterLvl = "CLUSTER"

-- | Data showed both per group and per cluster.
commonData :: [(String, String)]
commonData =[ ("N1_FAIL", "Nodes not N+1 happy")
            , ("CONFLICT_TAGS", "Nodes with conflicting instances")
            , ("OFFLINE_PRI", "Instances with primary on an offline node")
            , ("OFFLINE_SEC", "Instances with seondary on an offline node")
            ]

-- | Data showed per group.
groupData :: [(String, String)]
groupData = commonData ++ [("SCORE", "Group score")]

-- | Data showed per cluster.
clusterData :: [(String, String)]
clusterData = commonData ++
              [ ("NEED_REBALANCE", "Cluster is not healthy")
              , ("CAN_REBALANCE", "Possible to run rebalance")
              ]


-- | Format a list of key, value as a shell fragment.
printKeysHTC :: [(String, String)] -> IO ()
printKeysHTC = printKeys htcPrefix

-- | Prepare string from boolean value.
printBool :: Bool    -- ^ Whether the result should be machine readable
          -> Bool    -- ^ Value to be converted to string
          -> String
printBool True True = "1"
printBool True False = "0"
printBool False b = show b

-- | Print mapping from group idx to group uuid (only in machine readable mode).
printGroupsMappings :: Group.List -> IO ()
printGroupsMappings gl = do
    let extract_vals = \g -> (printf "GROUP_UUID_%d" $ Group.idx g :: String,
                              printf "%s" $ Group.uuid g :: String)
        printpairs = map extract_vals (Container.elems gl)
    printKeysHTC printpairs

-- | Print all the statistics on a group level.
printGroupStats :: Int -> Bool -> Phase -> Group.Group -> [Int] -> Double -> IO ()
printGroupStats _ True phase grp stats score = do
  let printstats = map (printf "%d") stats ++ [printf "%.8f" score] :: [String]
      printkeys = map (printf "%s_%s_%d_%s"
                                  (phasePrefix phase)
                                  (levelPrefix GroupLvl)
                                  (Group.idx grp))
                       (map fst groupData) :: [String]
  printKeysHTC (zip printkeys printstats)

printGroupStats verbose False phase grp stats score = do
  let printstats = map (printf "%d") stats ++ [printf "%.8f" score] :: [String]

  unless (verbose == 0) $ do
    printf "\nStatistics for group %s %s\n"
               (Group.name grp) (phaseDescription phase) :: IO ()
    mapM_ (\(a,b) -> printf "    %s: %s\n" (snd a) b :: IO ())
          (zip groupData printstats)

-- | Print all the statistics on a cluster (global) level.
printClusterStats :: Int -> Bool -> Phase -> [Int] -> Bool -> Bool -> IO ()
printClusterStats _ True phase stats needrebal canrebal = do
  let printstats = map (printf "%d") stats ++
                   map (printBool True) [needrebal, canrebal]
      printkeys = map (printf "%s_%s_%s"
                              (phasePrefix phase)
                              (levelPrefix ClusterLvl))
                      (map fst clusterData) :: [String]
  printKeysHTC (zip printkeys printstats)

printClusterStats verbose False phase stats needrebal canrebal = do
  let printstats = map (printf "%d") stats ++
                   map (printBool False) [needrebal, canrebal]
  unless (verbose == 0) $ do
      printf "\nCluster statistics %s\n" (phaseDescription phase) :: IO ()
      mapM_ (\(a,b) -> printf "    %s: %s\n" (snd a) b :: IO ())<commit_msg>Small reordering and renaming in hcheck<commit_after>{-| Cluster checker.

-}

{-

Copyright (C) 2012 Google Inc.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

You should have received a copy of the GNU Gene52al Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.

-}

module Ganeti.HTools.Program.Hcheck (main, options) where

import Control.Monad
import List (transpose)
import System.Exit
import System.IO
import Text.Printf (printf)

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

import qualified Ganeti.HTools.Program.Hbal as Hbal

import Ganeti.HTools.CLI
import Ganeti.HTools.ExtLoader
import Ganeti.HTools.Loader
import Ganeti.HTools.Types

-- | Options list and functions.
options :: [OptType]
options =
  [ oDataFile
  , oDiskMoves
  , oDynuFile
  , oEvacMode
  , oExInst
  , oExTags
  , oIAllocSrc
  , oInstMoves
  , oLuxiSocket
  , oMachineReadable
  , oMaxCpu
  , oMaxSolLength
  , oMinDisk
  , oMinGain
  , oMinGainLim
  , oMinScore
  , oNoSimulation
  , oOfflineNode
  , oQuiet
  , oRapiMaster
  , oSelInst
  , oShowHelp
  , oShowVer
  , oVerbose
  ]

-- | Check phase - are we before (initial) or after rebalance.
data Phase = Initial
           | Rebalanced

-- | Level of presented statistics.
data Level = GroupLvl
           | ClusterLvl

-- | Prefix for machine readable names
htcPrefix :: String
htcPrefix = "HCHECK"

-- | Data showed both per group and per cluster.
commonData :: [(String, String)]
commonData =[ ("N1_FAIL", "Nodes not N+1 happy")
            , ("CONFLICT_TAGS", "Nodes with conflicting instances")
            , ("OFFLINE_PRI", "Instances with primary on an offline node")
            , ("OFFLINE_SEC", "Instances with seondary on an offline node")
            ]

-- | Data showed per group.
groupData :: [(String, String)]
groupData = commonData ++ [("SCORE", "Group score")]

-- | Data showed per cluster.
clusterData :: [(String, String)]
clusterData = commonData ++
              [ ("NEED_REBALANCE", "Cluster is not healthy")
              , ("CAN_REBALANCE", "Possible to run rebalance")
              ]

-- | Phase-specific prefix for machine readable version.
phasePrefix :: Phase -> String
phasePrefix Initial = "INIT"
phasePrefix Rebalanced = "FINAL"

-- | Level-specific prefix for machine readable version.
levelPrefix :: Level -> String
levelPrefix GroupLvl = "GROUP"
levelPrefix ClusterLvl = "CLUSTER"

-- | Description of phases for human readable version.
phaseDescr :: Phase -> String
phaseDescr Initial = "initially"
phaseDescr Rebalanced = "after rebalancing"


-- | Format a list of key, value as a shell fragment.
printKeysHTC :: [(String, String)] -> IO ()
printKeysHTC = printKeys htcPrefix

-- | Prepare string from boolean value.
printBool :: Bool    -- ^ Whether the result should be machine readable
          -> Bool    -- ^ Value to be converted to string
          -> String
printBool True True = "1"
printBool True False = "0"
printBool False b = show b

-- | Print mapping from group idx to group uuid (only in machine readable mode).
printGroupsMappings :: Group.List -> IO ()
printGroupsMappings gl = do
    let extract_vals = \g -> (printf "GROUP_UUID_%d" $ Group.idx g :: String,
                              printf "%s" $ Group.uuid g :: String)
        printpairs = map extract_vals (Container.elems gl)
    printKeysHTC printpairs

-- | Print all the statistics on a group level.
printGroupStats :: Int -> Bool -> Phase -> Group.Group -> [Int] -> Double -> IO ()
printGroupStats _ True phase grp stats score = do
  let printstats = map (printf "%d") stats ++ [printf "%.8f" score] :: [String]
      printkeys = map (printf "%s_%s_%d_%s"
                                  (phasePrefix phase)
                                  (levelPrefix GroupLvl)
                                  (Group.idx grp))
                       (map fst groupData) :: [String]
  printKeysHTC (zip printkeys printstats)

printGroupStats verbose False phase grp stats score = do
  let printstats = map (printf "%d") stats ++ [printf "%.8f" score] :: [String]

  unless (verbose == 0) $ do
    printf "\nStatistics for group %s %s\n"
               (Group.name grp) (phaseDescr phase) :: IO ()
    mapM_ (\(a,b) -> printf "    %s: %s\n" (snd a) b :: IO ())
          (zip groupData printstats)

-- | Print all the statistics on a cluster (global) level.
printClusterStats :: Int -> Bool -> Phase -> [Int] -> Bool -> Bool -> IO ()
printClusterStats _ True phase stats needrebal canrebal = do
  let printstats = map (printf "%d") stats ++
                   map (printBool True) [needrebal, canrebal]
      printkeys = map (printf "%s_%s_%s"
                              (phasePrefix phase)
                              (levelPrefix ClusterLvl))
                      (map fst clusterData) :: [String]
  printKeysHTC (zip printkeys printstats)

printClusterStats verbose False phase stats needrebal canrebal = do
  let printstats = map (printf "%d") stats ++
                   map (printBool False) [needrebal, canrebal]
  unless (verbose == 0) $ do
      printf "\nCluster statistics %s\n" (phaseDescr phase) :: IO ()
      mapM_ (\(a,b) -> printf "    %s: %s\n" (snd a) b :: IO ())
{'fraction_non_alphanumeric': 0.10008510638297873, 'fraction_numerical': 0.004425531914893617, 'mean_word_length': 2.8527868852459015, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5510908', 'n_tokens_mistral': 3527, 'n_tokens_neox': 3395, 'n_words': 1265}