39 |
39 |
import qualified Control.Exception as E
|
40 |
40 |
import Control.Monad
|
41 |
41 |
import Data.Attoparsec.Text.Lazy as A
|
|
42 |
import Data.List
|
42 |
43 |
import Data.Text.Lazy (pack, unpack)
|
|
44 |
import Network.BSD (getHostName)
|
43 |
45 |
import System.Process
|
44 |
46 |
import qualified Text.JSON as J
|
45 |
47 |
|
46 |
48 |
import qualified Ganeti.BasicTypes as BT
|
47 |
49 |
import Ganeti.Common
|
|
50 |
import Ganeti.Confd.ClientFunctions
|
48 |
51 |
import Ganeti.DataCollectors.CLI
|
49 |
52 |
import Ganeti.DataCollectors.Types
|
|
53 |
import Ganeti.JSON
|
|
54 |
import Ganeti.Objects
|
50 |
55 |
import Ganeti.Storage.Lvm.LVParser
|
51 |
56 |
import Ganeti.Storage.Lvm.Types
|
52 |
57 |
import Ganeti.Utils
|
... | ... | |
81 |
86 |
|
82 |
87 |
-- | The data exported by the data collector, taken from the default location.
|
83 |
88 |
dcReport :: IO DCReport
|
84 |
|
dcReport = buildDCReport Nothing
|
|
89 |
dcReport = buildDCReport defaultOptions
|
85 |
90 |
|
86 |
91 |
-- * Command line options
|
87 |
92 |
|
... | ... | |
89 |
94 |
options =
|
90 |
95 |
return
|
91 |
96 |
[ oInputFile
|
|
97 |
, oConfdAddr
|
|
98 |
, oConfdPort
|
|
99 |
, oInstances
|
92 |
100 |
]
|
93 |
101 |
|
94 |
102 |
-- | The list of arguments supported by the program.
|
... | ... | |
103 |
111 |
params = lvParams
|
104 |
112 |
fromLvs =
|
105 |
113 |
((E.try $ readProcess cmd params "") :: IO (Either IOError String)) >>=
|
106 |
|
exitIfBad "running command" . either (BT.Bad . show) BT.Ok
|
|
114 |
exitIfBad "running command" . either (BT.Bad . show) BT.Ok
|
107 |
115 |
contents <-
|
108 |
116 |
maybe fromLvs (\fn -> ((E.try $ readFile fn) :: IO (Either IOError String))
|
109 |
117 |
>>= exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok)
|
... | ... | |
114 |
122 |
++ show contexts ++ "\n" ++ errorMessage
|
115 |
123 |
A.Done _ lvinfoD -> return lvinfoD
|
116 |
124 |
|
117 |
|
-- | This function computes the JSON representation of the LV status
|
118 |
|
buildJsonReport :: Maybe FilePath -> IO J.JSValue
|
119 |
|
buildJsonReport inputFile = do
|
|
125 |
-- | Get the list of instances on the current node (both primary and secondary)
|
|
126 |
-- either from a provided file or by querying Confd.
|
|
127 |
getInstanceList :: Options -> IO ([Instance], [Instance])
|
|
128 |
getInstanceList opts = do
|
|
129 |
let srvAddr = optConfdAddr opts
|
|
130 |
srvPort = optConfdPort opts
|
|
131 |
instFile = optInstances opts
|
|
132 |
fromConfdUnchecked :: IO (BT.Result ([Instance], [Instance]))
|
|
133 |
fromConfdUnchecked = getHostName >>= \n -> getInstances n srvAddr srvPort
|
|
134 |
fromConfd :: IO (BT.Result ([Instance], [Instance]))
|
|
135 |
fromConfd =
|
|
136 |
liftM (either (BT.Bad . show) id) (E.try fromConfdUnchecked ::
|
|
137 |
IO (Either IOError (BT.Result ([Instance], [Instance]))))
|
|
138 |
fromFile :: FilePath -> IO (BT.Result ([Instance], [Instance]))
|
|
139 |
fromFile inputFile = do
|
|
140 |
contents <-
|
|
141 |
((E.try $ readFile inputFile) :: IO (Either IOError String))
|
|
142 |
>>= exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok
|
|
143 |
return . fromJResult "Not a list of instances" $ J.decode contents
|
|
144 |
instances <- maybe fromConfd fromFile instFile
|
|
145 |
exitIfBad "Unable to obtain the list of instances" instances
|
|
146 |
|
|
147 |
-- | Adds the name of the instance to the information about one logical volume.
|
|
148 |
addInstNameToOneLv :: [Instance] -> LVInfo -> LVInfo
|
|
149 |
addInstNameToOneLv instances lvInfo =
|
|
150 |
let vg_name = lviVgName lvInfo
|
|
151 |
lv_name = lviName lvInfo
|
|
152 |
instanceHasDisk = any (includesLogicalId vg_name lv_name) . instDisks
|
|
153 |
rightInstance = find instanceHasDisk instances
|
|
154 |
in
|
|
155 |
case rightInstance of
|
|
156 |
Nothing -> lvInfo
|
|
157 |
Just i -> lvInfo { lviInstance = Just $ instName i }
|
|
158 |
|
|
159 |
-- | Adds the name of the instance to the information about logical volumes.
|
|
160 |
addInstNameToLv :: [Instance] -> [LVInfo] -> [LVInfo]
|
|
161 |
addInstNameToLv instances = map (addInstNameToOneLv instances)
|
|
162 |
|
|
163 |
-- | This function computes the JSON representation of the LV status.
|
|
164 |
buildJsonReport :: Options -> IO J.JSValue
|
|
165 |
buildJsonReport opts = do
|
|
166 |
let inputFile = optInputFile opts
|
120 |
167 |
lvInfo <- getLvInfo inputFile
|
121 |
|
return $ J.showJSON lvInfo
|
|
168 |
(prim, sec) <- getInstanceList opts
|
|
169 |
return . J.showJSON $ addInstNameToLv (prim ++ sec) lvInfo
|
122 |
170 |
|
123 |
171 |
-- | This function computes the DCReport for the logical volumes.
|
124 |
|
buildDCReport :: Maybe FilePath -> IO DCReport
|
125 |
|
buildDCReport inputFile =
|
126 |
|
buildJsonReport inputFile >>=
|
|
172 |
buildDCReport :: Options -> IO DCReport
|
|
173 |
buildDCReport opts =
|
|
174 |
buildJsonReport opts >>=
|
127 |
175 |
buildReport dcName dcVersion dcFormatVersion dcCategory dcKind
|
128 |
176 |
|
129 |
177 |
-- | Main function.
|
... | ... | |
131 |
179 |
main opts args = do
|
132 |
180 |
unless (null args) . exitErr $ "This program takes exactly zero" ++
|
133 |
181 |
" arguments, got '" ++ unwords args ++ "'"
|
134 |
|
report <- buildDCReport $ optInputFile opts
|
135 |
182 |
|
|
183 |
report <- buildDCReport opts
|
136 |
184 |
putStrLn $ J.encode report
|