Commit 31b430c5 authored by Ilias Tsitsimpis's avatar Ilias Tsitsimpis Committed by Jose A. Lopes

Implement getDisks in Confd

Add 'ReqInstanceDisks' request type and allow Confd to query for the
disks of an instance. The helper function 'getInstanceDisks' returns the
list of instances on the given node along with their disks and is used
by the function 'addInstNameToLv'.

Update the test's data file 'instance-prim-sec' and rename it to
'instance-disks' as it doesn't return the primary and secondary
instances of a node any more, but it returns the instances and their
disks.
Signed-off-by: default avatarIlias Tsitsimpis <iliastsi@grnet.gr>
Reviewed-by: default avatarJose A. Lopes <jabolopes@google.com>
parent e9ebf2d7
......@@ -1448,7 +1448,7 @@ TEST_FILES = \
test/data/cluster_config_2.10.json \
test/data/cluster_config_2.11.json \
test/data/instance-minor-pairing.txt \
test/data/instance-prim-sec.txt \
test/data/instance-disks.txt \
test/data/ip-addr-show-dummy0.txt \
test/data/ip-addr-show-lo-ipv4.txt \
test/data/ip-addr-show-lo-ipv6.txt \
......
......@@ -25,8 +25,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
module Ganeti.Confd.ClientFunctions
( getInstances
, getInstanceDisks
) where
import Control.Monad (liftM)
import qualified Text.JSON as J
import Ganeti.BasicTypes as BT
......@@ -42,12 +44,39 @@ getInstances
:: String
-> Maybe String
-> Maybe Int
-> IO (BT.Result ([Ganeti.Objects.Instance], [Ganeti.Objects.Instance]))
-> BT.ResultT String IO ([Ganeti.Objects.Instance], [Ganeti.Objects.Instance])
getInstances node srvAddr srvPort = do
client <- getConfdClient srvAddr srvPort
reply <- query client ReqNodeInstances $ PlainQuery node
return $
case fmap (J.readJSON . confdReplyAnswer) reply of
Just (J.Ok instances) -> BT.Ok instances
Just (J.Error msg) -> BT.Bad msg
Nothing -> BT.Bad "No answer from the Confd server"
client <- liftIO $ getConfdClient srvAddr srvPort
reply <- liftIO . query client ReqNodeInstances $ PlainQuery node
case fmap (J.readJSON . confdReplyAnswer) reply of
Just (J.Ok instances) -> return instances
Just (J.Error msg) -> fail msg
Nothing -> fail "No answer from the Confd server"
-- | Get the list of disks that belong to a given instance
-- The server address and the server port parameters are mainly intended
-- for testing purposes. If they are Nothing, the default values will be used.
getDisks
:: Ganeti.Objects.Instance
-> Maybe String
-> Maybe Int
-> BT.ResultT String IO [Ganeti.Objects.Disk]
getDisks inst srvAddr srvPort = do
client <- liftIO $ getConfdClient srvAddr srvPort
reply <- liftIO . query client ReqInstanceDisks . PlainQuery . instUuid $ inst
case fmap (J.readJSON . confdReplyAnswer) reply of
Just (J.Ok disks) -> return disks
Just (J.Error msg) -> fail msg
Nothing -> fail "No answer from the Confd server"
-- | Get the list of instances on the given node along with their disks
-- The server address and the server port parameters are mainly intended
-- for testing purposes. If they are Nothing, the default values will be used.
getInstanceDisks
:: String
-> Maybe String
-> Maybe Int
-> BT.ResultT String IO [(Ganeti.Objects.Instance, [Ganeti.Objects.Disk])]
getInstanceDisks node srvAddr srvPort =
liftM (uncurry (++)) (getInstances node srvAddr srvPort) >>=
mapM (\i -> liftM ((,) i) (getDisks i srvAddr srvPort))
......@@ -221,6 +221,17 @@ buildResponse cdata req@(ConfdRequest { confdRqType = ReqNodeInstances }) = do
instances = getNodeInstances cfg node_uuid
return (ReplyStatusOk, J.showJSON instances)
-- | Return the list of disks for an instance given the instance uuid.
buildResponse cdata req@(ConfdRequest { confdRqType = ReqInstanceDisks }) = do
let cfg = fst cdata
inst_uuid <-
case confdRqQuery req of
PlainQuery str -> return str
_ -> fail $ "Invalid query type " ++ show (confdRqQuery req)
case getInstDisksByName cfg inst_uuid of
Ok disks -> return (ReplyStatusOk, J.showJSON disks)
Bad e -> fail $ "Could not retrieve disks: " ++ show e
-- | Creates a ConfdReply from a given answer.
serializeResponse :: Result StatusAnswer -> ConfdReply
serializeResponse r =
......
......@@ -63,6 +63,7 @@ $(declareILADT "ConfdRequestType"
, ("ReqInstIpsList", 6)
, ("ReqNodeDrbd", 7)
, ("ReqNodeInstances", 8)
, ("ReqInstanceDisks", 9)
])
$(makeJSONInstance ''ConfdRequestType)
......
......@@ -4084,6 +4084,9 @@ confdReqNodeDrbd = Types.confdRequestTypeToRaw ReqNodeDrbd
confdReqNodeInstances :: Int
confdReqNodeInstances = Types.confdRequestTypeToRaw ReqNodeInstances
confdReqInstanceDisks :: Int
confdReqInstanceDisks = Types.confdRequestTypeToRaw ReqInstanceDisks
confdReqs :: FrozenSet Int
confdReqs =
ConstantUtils.mkSet .
......
......@@ -180,7 +180,7 @@ computeGlobalStatus instStatusList =
buildInstStatusReport :: Maybe String -> Maybe Int -> IO DCReport
buildInstStatusReport srvAddr srvPort = do
node <- getHostName
answer <- getInstances node srvAddr srvPort
answer <- runResultT $ getInstances node srvAddr srvPort
inst <- exitIfBad "Can't get instance info from ConfD" answer
d <- getInferredDomInfo
reportData <-
......
......@@ -122,51 +122,55 @@ getLvInfo inputFile = do
++ show contexts ++ "\n" ++ errorMessage
A.Done _ lvinfoD -> return lvinfoD
-- | Get the list of instances on the current node (both primary and secondary)
-- | Get the list of instances on the current node along with their disks,
-- 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
getInstDiskList :: Options -> IO [(Instance, [Disk])]
getInstDiskList opts = do
instances <- maybe fromConfd fromFile $ optInstances opts
exitIfBad "Unable to obtain the list of instances" instances
where
fromConfdUnchecked :: IO (BT.Result [(Instance, [Disk])])
fromConfdUnchecked = do
let srvAddr = optConfdAddr opts
srvPort = optConfdPort opts
getHostName >>= \n -> BT.runResultT $ getInstanceDisks n srvAddr srvPort
fromConfd :: IO (BT.Result [(Instance, [Disk])])
fromConfd =
liftM (either (BT.Bad . show) id)
(E.try fromConfdUnchecked ::
IO (Either IOError (BT.Result [(Instance, [Disk])])))
fromFile :: FilePath -> IO (BT.Result [(Instance, [Disk])])
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
-- | 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 }
addInstNameToOneLv :: [(Instance, [Disk])] -> LVInfo -> LVInfo
addInstNameToOneLv instDiskList lvInfo =
let vg_name = lviVgName lvInfo
lv_name = lviName lvInfo
instanceHasDisk = any (includesLogicalId vg_name lv_name) . snd
rightInstance = find instanceHasDisk instDiskList
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)
addInstNameToLv :: [(Instance, [Disk])] -> [LVInfo] -> [LVInfo]
addInstNameToLv instDisksList = map (addInstNameToOneLv instDisksList)
-- | 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
(prim, sec) <- getInstanceList opts
return . J.showJSON $ addInstNameToLv (prim ++ sec) lvInfo
instDiskList <- getInstDiskList opts
return . J.showJSON $ addInstNameToLv instDiskList lvInfo
-- | This function computes the DCReport for the logical volumes.
buildDCReport :: Options -> IO DCReport
......
......@@ -85,4 +85,68 @@
"primary_node": "60e687a0-21fc-4577-997f-ccd08925fa65",
"serial_no": 2,
"uuid": "aec390cb-5eae-44e6-bcc2-ec14d31347f0"
}], []]
},
[{
"children": [
{
"dev_type": "plain",
"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",
"serial_no": 1,
"ctime": 1372838946.2599809,
"mtime": 1372838946.2599809
},
{
"dev_type": "plain",
"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",
"serial_no": 1,
"mtime": 1372838946.2599809,
"ctime": 1372838946.2599809
}
],
"dev_type": "drbd",
"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",
"serial_no": 1,
"ctime": 1372838946.2599809,
"mtime": 1372838946.2599809
}]]
]
......@@ -104,6 +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 -i $PYTESTDATA_DIR/instance-prim-sec.txt
./test/hs/hpc-mon-collector lv -f $PYTESTDATA_DIR/lvs_lv.txt -i $PYTESTDATA_DIR/instance-disks.txt
>>>/"instance":"instance1.example.com"/
>>>= 0
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment