Safe HaskellSafe-Infered




KVM daemon

The KVM daemon is responsible for determining whether a given KVM instance was shutdown by an administrator or a user. For more information read the design document on the KVM daemon.

The KVM daemon design is split in 2 parts, namely, monitors for Qmp sockets and directory/file watching.

The monitors are spawned in lightweight Haskell threads and are reponsible for handling the communication between the KVM daemon and the KVM instance using the Qmp protocol. During the communcation, the monitor parses the Qmp messages and if powerdown or shutdown is received, then the shutdown file is written in the KVM control directory. Otherwise, when the communication terminates, that same file is removed. The communication terminates when the KVM instance stops or crashes.

The directory and file watching uses inotify to track down events on the KVM control directory and its parents. There is a directory crawler that will try to add a watch to the KVM control directory if available or its parents, thus replacing watches until the KVM control directory becomes available. When this happens, a monitor for the Qmp socket is spawned. Given that the KVM daemon might stop or crash, the directory watching also simulates events for the Qmp sockets that already exist in the KVM control directory when the KVM daemon starts.



type Lock = MVar ()Source

type Monitors = MVar (Set FilePath)Source


isPrefixPath :: FilePath -> FilePath -> BoolSource

isPrefixPath x y determines whether x is a FilePath prefix of FilePath y.

monitorDir :: StringSource

KVM control directory containing the Qmp sockets.

isMonitorPath :: FilePath -> BoolSource

shutdownPath :: String -> StringSource

touchFile :: FilePath -> IO ()Source

Monitors for Qmp sockets

parseQmp :: Bool -> Bool -> Bool -> String -> (Bool, Bool, Bool)Source

parseQmp isPowerdown isShutdown isStop str parses the packet str and returns whether a powerdown, shutdown, or stop event is contained in that packet, defaulting to the values isPowerdown, isShutdown, and isStop, otherwise.

receiveQmp :: Handle -> IO BoolSource

receiveQmp handle listens for Qmp events on handle and, when handle is closed, it returns True if a user shutdown event was received, and False otherwise.

detectMonitor :: FilePath -> Handle -> IO ()Source

detectMonitor monitorFile handle listens for Qmp events on handle for Qmp socket monitorFile and, when communcation terminates, it either creates the shutdown file, if a user shutdown was detected, or it deletes that same file, if an administrator shutdown was detected.

runMonitor :: FilePath -> IO ()Source

runMonitor monitorFile creates a monitor for the Qmp socket monitorFile and calls detectMonitor.

ensureMonitor :: Monitors -> FilePath -> IO ()Source

ensureMonitor monitors monitorFile ensures that there is exactly one monitor running for the Qmp socket monitorFile, given the existing set of monitors monitors.

Directory and file watching

handleGenericEvent :: Lock -> String -> String -> Event -> IO ()Source

Handles an inotify event outside the target directory.

Tracks events on the parent directory of the KVM control directory until one of its parents becomes available.

handleTargetEvent :: Lock -> Monitors -> String -> Event -> IO ()Source

Handles an inotify event in the target directory.

Upon a create or open event inside the KVM control directory, it ensures that there is a monitor running for the new Qmp socket.

handleDir :: Lock -> Monitors -> String -> String -> Event -> IO ()Source

Dispatches inotify events depending on the directory they occur in.

recapDir :: Lock -> Monitors -> FilePath -> IO ()Source

Simulates file creation events for the Qmp sockets that already exist in dir.

watchDir :: Lock -> FilePath -> INotify -> IO ()Source

Crawls tarDir, or its parents until tarDir becomes available, always listening for inotify events.

Used for crawling the KVM control directory and its parents, as well as simulating file creation events.

rewatchDir :: Lock -> FilePath -> INotify -> IO ()Source

Starting point

startWith :: FilePath -> IO ()Source

start :: IO ()Source