This commit enables the logical volume data collector to get information about the instances and to link it to the information about logical volumes.
The list of parameters accepted by the collector is expanded to allow proper testing and connections to Confd in non-standard locations. The shelltest test is updated accordingly. Signed-off-by: Michele Tartara <[email protected]> --- Makefile.am | 1 + src/Ganeti/DataCollectors/Lv.hs | 68 ++++++++++++++++++++---- test/data/instance-prim-sec.txt | 78 ++++++++++++++++++++++++++++ test/hs/shelltests/htools-mon-collector.test | 3 +- 4 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 test/data/instance-prim-sec.txt diff --git a/Makefile.am b/Makefile.am index 64109a8..dd9dbd2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1134,6 +1134,7 @@ TEST_FILES = \ test/data/cluster_config_2.7.json \ test/data/cluster_config_2.8.json \ test/data/instance-minor-pairing.txt \ + test/data/instance-prim-sec.txt \ test/data/ip-addr-show-dummy0.txt \ test/data/ip-addr-show-lo-ipv4.txt \ test/data/ip-addr-show-lo-ipv6.txt \ diff --git a/src/Ganeti/DataCollectors/Lv.hs b/src/Ganeti/DataCollectors/Lv.hs index 5c4abcd..d296b0f 100644 --- a/src/Ganeti/DataCollectors/Lv.hs +++ b/src/Ganeti/DataCollectors/Lv.hs @@ -39,14 +39,19 @@ module Ganeti.DataCollectors.Lv import qualified Control.Exception as E import Control.Monad import Data.Attoparsec.Text.Lazy as A +import Data.List import Data.Text.Lazy (pack, unpack) +import Network.BSD (getHostName) import System.Process import qualified Text.JSON as J import qualified Ganeti.BasicTypes as BT import Ganeti.Common +import Ganeti.Confd.ClientFunctions import Ganeti.DataCollectors.CLI import Ganeti.DataCollectors.Types +import Ganeti.JSON +import Ganeti.Objects import Ganeti.Storage.Lvm.LVParser import Ganeti.Storage.Lvm.Types import Ganeti.Utils @@ -81,7 +86,7 @@ dcKind = DCKPerf -- | The data exported by the data collector, taken from the default location. dcReport :: IO DCReport -dcReport = buildDCReport Nothing +dcReport = buildDCReport defaultOptions -- * Command line options @@ -89,6 +94,9 @@ options :: IO [OptType] options = return [ oInputFile + , oConfdAddr + , oConfdPort + , oInstances ] -- | The list of arguments supported by the program. @@ -103,7 +111,7 @@ getLvInfo inputFile = do params = lvParams fromLvs = ((E.try $ readProcess cmd params "") :: IO (Either IOError String)) >>= - exitIfBad "running command" . either (BT.Bad . show) BT.Ok + exitIfBad "running command" . either (BT.Bad . show) BT.Ok contents <- maybe fromLvs (\fn -> ((E.try $ readFile fn) :: IO (Either IOError String)) >>= exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok) @@ -114,16 +122,56 @@ getLvInfo inputFile = do ++ show contexts ++ "\n" ++ errorMessage A.Done _ lvinfoD -> return lvinfoD --- | This function computes the JSON representation of the LV status -buildJsonReport :: Maybe FilePath -> IO J.JSValue -buildJsonReport inputFile = do +-- | Get the list of instances on the current node (both primary and secondary) +-- either from a provided file or by querying Confd. +getInstanceList :: Options -> IO ([Instance], [Instance]) +getInstanceList opts = do + let srvAddr = optConfdAddr opts + srvPort = optConfdPort opts + instFile = optInstances opts + fromConfdUnchecked :: IO (BT.Result ([Instance], [Instance])) + fromConfdUnchecked = getHostName >>= \n -> getInstances n srvAddr srvPort + fromConfd :: IO (BT.Result ([Instance], [Instance])) + fromConfd = + liftM (either (BT.Bad . show) id) (E.try fromConfdUnchecked :: + IO (Either IOError (BT.Result ([Instance], [Instance])))) + fromFile :: FilePath -> IO (BT.Result ([Instance], [Instance])) + fromFile inputFile = do + contents <- + ((E.try $ readFile inputFile) :: IO (Either IOError String)) + >>= exitIfBad "reading from file" . either (BT.Bad . show) BT.Ok + return . fromJResult "Not a list of instances" $ J.decode contents + instances <- maybe fromConfd fromFile instFile + exitIfBad "Unable to obtain the list of instances" instances + +-- | Adds the name of the instance to the information about one logical volume. +addInstNameToOneLv :: [Instance] -> LVInfo -> LVInfo +addInstNameToOneLv instances lvInfo = + let vg_name = lviVgName lvInfo + lv_name = lviName lvInfo + instanceHasDisk = any (includesLogicalId vg_name lv_name) . instDisks + rightInstance = find instanceHasDisk instances + in + case rightInstance of + Nothing -> lvInfo + Just i -> lvInfo { lviInstance = Just $ instName i } + +-- | Adds the name of the instance to the information about logical volumes. +addInstNameToLv :: [Instance] -> [LVInfo] -> [LVInfo] +addInstNameToLv instances = map (addInstNameToOneLv instances) + +-- | This function computes the JSON representation of the LV status. +buildJsonReport :: Options -> IO J.JSValue +buildJsonReport opts = do + let inputFile = optInputFile opts lvInfo <- getLvInfo inputFile - return $ J.showJSON lvInfo + (prim, sec) <- getInstanceList opts + return . J.showJSON $ addInstNameToLv (prim ++ sec) lvInfo -- | This function computes the DCReport for the logical volumes. -buildDCReport :: Maybe FilePath -> IO DCReport -buildDCReport inputFile = - buildJsonReport inputFile >>= +buildDCReport :: Options -> IO DCReport +buildDCReport opts = + buildJsonReport opts >>= buildReport dcName dcVersion dcFormatVersion dcCategory dcKind -- | Main function. @@ -131,6 +179,6 @@ main :: Options -> [String] -> IO () main opts args = do unless (null args) . exitErr $ "This program takes exactly zero" ++ " arguments, got '" ++ unwords args ++ "'" - report <- buildDCReport $ optInputFile opts + report <- buildDCReport opts putStrLn $ J.encode report diff --git a/test/data/instance-prim-sec.txt b/test/data/instance-prim-sec.txt new file mode 100644 index 0000000..76fa512 --- /dev/null +++ b/test/data/instance-prim-sec.txt @@ -0,0 +1,78 @@ +[[{"admin_state": "up", + "beparams": {}, + "ctime": 1372838883.9710441, + "disk_template": "drbd", + "disks": [ + { + "children": [ + { + "dev_type": "lvm", + "logical_id": [ + "xenvg", + "df9ff3f6-a833-48ff-8bd5-bff2eaeab759.disk0_data" + ], + "params": {}, + "physical_id": [ + "xenvg", + "df9ff3f6-a833-48ff-8bd5-bff2eaeab759.disk0_data" + ], + "size": 1024, + "uuid": "eaff6322-1bfb-4d59-b306-4535730917cc" + }, + { + "dev_type": "lvm", + "logical_id": [ + "xenvg", + "df9ff3f6-a833-48ff-8bd5-bff2eaeab759.disk0_meta" + ], + "params": {}, + "physical_id": [ + "xenvg", + "df9ff3f6-a833-48ff-8bd5-bff2eaeab759.disk0_meta" + ], + "size": 128, + "uuid": "bf512e95-2a49-4cb3-8d1f-30a503f6bf1b" + } + ], + "dev_type": "drbd8", + "iv_name": "disk/0", + "logical_id": [ + "60e687a0-21fc-4577-997f-ccd08925fa65", + "c739c7f3-79d8-4e20-ac68-662e16577d2e", + 11000, + 0, + 0, + "9bdb15fb7ab6bb4610a313d654ed4d0d2433713e" + ], + "mode": "rw", + "params": {}, + "physical_id": [ + "172.16.241.3", + 11000, + "172.16.241.2", + 11000, + 0, + "9bdb15fb7ab6bb4610a313d654ed4d0d2433713e" + ], + "size": 1024, + "uuid": "5d61e205-bf89-4ba8-a319-589b7bb7419e" + } + ], + "disks_active": true, + "hvparams": {}, + "hypervisor": "xen-pvm", + "mtime": 1372838946.2599809, + "name": "instance1.example.com", + "nics": [ + { + "mac": "aa:00:00:1d:ba:63", + "nicparams": {}, + "uuid": "7b7f4249-fab8-4b3f-b446-d7a2aff37644" + } + ], + "os": "busybox", + "osparams": {}, + "primary_node": "60e687a0-21fc-4577-997f-ccd08925fa65", + "serial_no": 2, + "uuid": "aec390cb-5eae-44e6-bcc2-ec14d31347f0" + }], []] diff --git a/test/hs/shelltests/htools-mon-collector.test b/test/hs/shelltests/htools-mon-collector.test index 7ad1fbb..6fcecbd 100644 --- a/test/hs/shelltests/htools-mon-collector.test +++ b/test/hs/shelltests/htools-mon-collector.test @@ -104,5 +104,6 @@ Failed reading: versionInfo >>>= !0 # Test that lv parses correctly a standard test file -./test/hs/hpc-mon-collector lv -f $PYTESTDATA_DIR/lvs_lv.txt +./test/hs/hpc-mon-collector lv -f $PYTESTDATA_DIR/lvs_lv.txt -i $PYTESTDATA_DIR/instance-prim-sec.txt +>>>/"instance":"instance1.example.com"/ >>>= 0 -- 1.8.3
