module Ganeti.Locking.Locks
( GanetiLocks(..)
, lockName
, ClientType(..)
, ClientId(..)
, GanetiLockWaiting
, LockLevel(..)
, lockLevel
) where
import Control.Monad ((>=>), liftM)
import Data.List (stripPrefix)
import System.Posix.Types (ProcessID)
import qualified Text.JSON as J
import Ganeti.JSON (readEitherString)
import Ganeti.Locking.Types
import Ganeti.Locking.Waiting
import Ganeti.Types
data GanetiLocks = ClusterLockSet
| BGL
| InstanceLockSet
| Instance String
| NodeGroupLockSet
| NodeGroup String
| NodeLockSet
| Node String
| NodeResLockSet
| NodeRes String
| NetworkLockSet
| Network String
| ConfigLock
deriving (Ord, Eq, Show)
lockName :: GanetiLocks -> String
lockName BGL = "cluster/BGL"
lockName ClusterLockSet = "cluster/[lockset]"
lockName InstanceLockSet = "instance/[lockset]"
lockName (Instance uuid) = "instance/" ++ uuid
lockName NodeGroupLockSet = "nodegroup/[lockset]"
lockName (NodeGroup uuid) = "nodegroup/" ++ uuid
lockName NodeLockSet = "node/[lockset]"
lockName (Node uuid) = "node/" ++ uuid
lockName NodeResLockSet = "node-res/[lockset]"
lockName (NodeRes uuid) = "node-res/" ++ uuid
lockName NetworkLockSet = "network/[lockset]"
lockName (Network uuid) = "network/" ++ uuid
lockName ConfigLock = "cluster/config"
lockFromName :: String -> J.Result GanetiLocks
lockFromName "cluster/BGL" = return BGL
lockFromName "cluster/[lockset]" = return ClusterLockSet
lockFromName "instance/[lockset]" = return InstanceLockSet
lockFromName (stripPrefix "instance/" -> Just uuid) = return $ Instance uuid
lockFromName "nodegroup/[lockset]" = return NodeGroupLockSet
lockFromName (stripPrefix "nodegroup/" -> Just uuid) = return $ NodeGroup uuid
lockFromName "node-res/[lockset]" = return NodeResLockSet
lockFromName (stripPrefix "node-res/" -> Just uuid) = return $ NodeRes uuid
lockFromName "node/[lockset]" = return NodeLockSet
lockFromName (stripPrefix "node/" -> Just uuid) = return $ Node uuid
lockFromName "network/[lockset]" = return NetworkLockSet
lockFromName (stripPrefix "network/" -> Just uuid) = return $ Network uuid
lockFromName "cluster/config" = return ConfigLock
lockFromName n = fail $ "Unknown lock name '" ++ n ++ "'"
instance J.JSON GanetiLocks where
showJSON = J.JSString . J.toJSString . lockName
readJSON = readEitherString >=> lockFromName
data LockLevel = LevelCluster
| LevelInstance
| LevelNodeGroup
| LevelNode
| LevelNodeRes
| LevelNetwork
| LevelConfig
deriving (Eq, Show, Enum)
lockLevelName :: LockLevel -> String
lockLevelName LevelCluster = "cluster"
lockLevelName LevelInstance = "instance"
lockLevelName LevelNodeGroup = "nodegroup"
lockLevelName LevelNode = "node"
lockLevelName LevelNodeRes = "node-res"
lockLevelName LevelNetwork = "network"
lockLevelName LevelConfig = "config"
lockLevelFromName :: String -> J.Result LockLevel
lockLevelFromName "cluster" = return LevelCluster
lockLevelFromName "instance" = return LevelInstance
lockLevelFromName "nodegroup" = return LevelNodeGroup
lockLevelFromName "node" = return LevelNode
lockLevelFromName "node-res" = return LevelNodeRes
lockLevelFromName "network" = return LevelNetwork
lockLevelFromName "config" = return LevelConfig
lockLevelFromName n = fail $ "Unknown lock-level name '" ++ n ++ "'"
instance J.JSON LockLevel where
showJSON = J.JSString . J.toJSString . lockLevelName
readJSON = readEitherString >=> lockLevelFromName
lockLevel :: GanetiLocks -> LockLevel
lockLevel BGL = LevelCluster
lockLevel ClusterLockSet = LevelCluster
lockLevel InstanceLockSet = LevelInstance
lockLevel (Instance _) = LevelInstance
lockLevel NodeGroupLockSet = LevelNodeGroup
lockLevel (NodeGroup _) = LevelNodeGroup
lockLevel NodeLockSet = LevelNode
lockLevel (Node _) = LevelNode
lockLevel NodeResLockSet = LevelNodeRes
lockLevel (NodeRes _) = LevelNodeRes
lockLevel NetworkLockSet = LevelNetwork
lockLevel (Network _) = LevelNetwork
lockLevel ConfigLock = LevelConfig
instance Lock GanetiLocks where
lockImplications BGL = [ClusterLockSet]
lockImplications (Instance _) = [InstanceLockSet]
lockImplications (NodeGroup _) = [NodeGroupLockSet]
lockImplications (NodeRes _) = [NodeResLockSet]
lockImplications (Node _) = [NodeLockSet]
lockImplications (Network _) = [NetworkLockSet]
lockImplications ConfigLock = []
lockImplications _ = []
data ClientType = ClientOther String
| ClientJob JobId
deriving (Ord, Eq, Show)
instance J.JSON ClientType where
showJSON (ClientOther s) = J.showJSON s
showJSON (ClientJob jid) = J.showJSON jid
readJSON (J.JSString s) = J.Ok . ClientOther $ J.fromJSString s
readJSON jids = J.readJSON jids >>= \jid -> J.Ok (ClientJob jid)
data ClientId = ClientId
{ ciIdentifier :: ClientType
, ciLockFile :: FilePath
, ciPid :: ProcessID
}
deriving (Ord, Eq, Show)
clientIdFromJSON :: J.JSValue -> J.Result ClientId
clientIdFromJSON (J.JSArray [clienttp, J.JSString lf, pid]) =
ClientId <$> J.readJSON clienttp <*> pure (J.fromJSString lf)
<*> liftM fromIntegral (J.readJSON pid :: J.Result Integer)
clientIdFromJSON x = J.Error $ "malformed client id: " ++ show x
instance J.JSON ClientId where
showJSON (ClientId client lf pid)
= J.showJSON (client, lf, fromIntegral pid :: Integer)
readJSON = clientIdFromJSON
type GanetiLockWaiting = LockWaiting GanetiLocks ClientId Integer