packages feed

scrz-0.0.0.1: src/Scrz/Main.hs

module Main where

import Control.Monad
import System.Environment
import System.Directory
import System.Posix.Process
import System.Posix.IO
import System.Posix.Terminal (openPseudoTerminal, getSlaveTerminalName)

import Control.Exception
import Control.Concurrent

import Scrz.Protocol
import Scrz.Commands
import Scrz.Image
import Scrz.Log
import Scrz.Proxy
import Scrz.Socket
import Scrz.Terminal
import Scrz.Types
import Scrz.Utils
import Scrz.Supervisor



run :: [ String ] -> IO ()

run [ "supervisor" ]                 = startSupervisor Nothing
run [ "supervisor", url ]            = startSupervisor (Just url)

run [ "ipvs", addr, url ]            = ipvsProxy addr url

run [ "inspect", id' ]               = inspectContainer id'
run [ "ps" ]                         = listContainers
run [ "list-containers" ]            = listContainers
run [ "stop-container", id' ]        = stopContainer id'
run [ "destroy-container", id' ]     = destroyContainer id'
run [ "start", id' ]                 = startContainer id'
run [ "stop", id' ]                  = stopContainer id'
run [ "restart", id' ]               = stopContainer id' >> startContainer id'
run [ "quit" ]                       = quitSupervisor
run [ "snapshot", container, image ] = snapshotContainer container image
run [ "pack-image", id' ]            = packImage id'
run [ "list-images" ]                = listImages
run [ "destroy-image", id' ]         = destroyImage id'
run [ "download-image", url, checksum, size ] = downloadImage url checksum (read size)


run [ "console", id' ] = do
    executeFile "lxc-console" True [ "-n", id' ] Nothing


run [ "clone-image", localImageId, newImageId ] = do
    let srcImage = Image localImageId Nothing
    let dstImage = Image newImageId Nothing

    createDirectoryIfMissing True (imageBasePath dstImage)
    cloneImage srcImage (imageVolumePath dstImage)


run ("run":args) = do
    (ptm, pts) <- openPseudoTerminal
    attrs      <- setRawModeFd stdInput

    response <- finally (sendRunCommand ptm) (freeResources ptm pts attrs) `catch` \(_ :: SomeException) -> return ErrorResponse

    logger $ show response
    handleResponse response `onException` do
        logger $ "Got exception"


  where
    ra = parseRunArguments (RunArgs "" [] [] Nothing) args
    pump src dst = fdRead src 999 >>= \(x, _) -> fdWrite dst x

    freeResources ptm pts attrs = do
        resetModeFd stdInput attrs
        closeFd ptm
        closeFd pts

    sendRunCommand ptm = do
        void $ forkFinally (forever $ pump ptm stdOutput) (const $ return ())
        void $ forkFinally (forever $ pump stdInput ptm)  (const $ return ())

        slaveName <- getSlaveTerminalName ptm
        response  <- sendCommand $ Run (runArgsImage ra) (runArgsCommand ra) slaveName (runArgsMounts ra)

        case response of
            CreateContainerResponse id' -> void $ sendCommand $ Wait id'
            _ -> return ()

        return response

    handleResponse response = do
        case response of
            CreateContainerResponse id' -> do
                imageId' <- maybe newId return (runArgsSaveAs ra)
                logger $ "Saving image under id " ++ imageId'
                void $ sendCommand $ Snapshot id' imageId'
                void $ sendCommand $ DestroyContainer id'

            _ -> do
                logger $ "Received unexpected response: " ++ show response


run args = do
    logger $ "Unknown arguments: " ++ (show args)


data RunArgs = RunArgs
  { runArgsImage :: String
  , runArgsCommand :: [String]
  , runArgsMounts :: [(String,String)]
  , runArgsSaveAs :: Maybe String
  } deriving (Show)

parseRunArguments :: RunArgs -> [String] -> RunArgs
parseRunArguments ra ("--save-as" : id' : args) =
    let pra = ra { runArgsSaveAs = Just id' }
    in parseRunArguments pra args

parseRunArguments ra ("--mount" : bv : mp : args) =
    let pra = ra { runArgsMounts = (bv,mp) : runArgsMounts ra }
    in parseRunArguments pra args

parseRunArguments ra (image : command) =
    ra { runArgsImage = image, runArgsCommand = command }

parseRunArguments ra [] = ra

main :: IO ()
main = getArgs >>= run