-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Running worker processes under system resource restrictions -- -- This library provides an abstract interface for running various kinds -- of workers under resource restrictions. It was originally developed as -- part of the interactive-diagrams -- (http://github.com/co-dan/interactive-diagrams) project. To -- read more about the idia behind the library check out my GSoC report: -- http://parenz.wordpress.com/2013/07/15/interactive-diagrams-gsoc-progress-report/. -- -- The library provides a convenient way of running worker processes, -- saving data obtained by the workers at start-up, a simple pool -- abstraction and a configurable security and resource limitations. -- Please consult -- https://github.com/co-dan/interactive-diagrams/tree/master/restricted-workers/README.md -- and -- https://github.com/co-dan/interactive-diagrams/wiki/Restricted-Workers -- for more details. -- -- Warning: this library requires SELinux to function @package restricted-workers @version 0.1.0 module System.Restricted.Types -- | Datastructure that holds the information about restrictions and -- limitations for the worker process data LimitSettings LimitSettings :: Int -> Int -> Maybe RLimits -> Maybe FilePath -> Maybe UserID -> Maybe SecurityContext -> Maybe FilePath -> LimitSettings -- | Maximum time for which the code is allowed to run (in seconds) timeout :: LimitSettings -> Int -- | Process priority for the nice syscall. -20 is the highest, 20 -- is the lowest niceness :: LimitSettings -> Int -- | Resource limits for the setrlimit syscall rlimits :: LimitSettings -> Maybe RLimits -- | The directory that the evaluator process will be chrooted -- into. Please note that if chroot is applied, all the pathes in -- EvalSettings will be calculated relatively to this value. chrootPath :: LimitSettings -> Maybe FilePath -- | The UID that will be set after the call to chroot. processUid :: LimitSettings -> Maybe UserID -- | SELinux security context under which the worker process will be -- running. secontext :: LimitSettings -> Maybe SecurityContext -- | A filepath to the tasks file for the desired cgroup. -- -- For example, if I have mounted the cpu controller at -- cgroupscpu/ and I want the evaluator to be running in -- the cgroup idiaworkers then the cgroupPath would be -- cgroupscpu/idiaworkers cgroupPath :: LimitSettings -> Maybe FilePath -- | Resource limits data RLimits RLimits :: ResourceLimits -> ResourceLimits -> ResourceLimits -> ResourceLimits -> ResourceLimits -> ResourceLimits -> ResourceLimits -> RLimits coreFileSizeLimit :: RLimits -> ResourceLimits cpuTimeLimit :: RLimits -> ResourceLimits dataSizeLimit :: RLimits -> ResourceLimits fileSizeLimit :: RLimits -> ResourceLimits openFilesLimit :: RLimits -> ResourceLimits stackSizeLimit :: RLimits -> ResourceLimits totalMemoryLimit :: RLimits -> ResourceLimits -- | Default LimitSettings defaultLimits :: LimitSettings instance Generic CUid instance Generic ResourceLimits instance Generic ResourceLimit instance Show Resource instance Show ResourceLimit instance Show ResourceLimits instance Eq RLimits instance Show RLimits instance Generic RLimits instance Eq LimitSettings instance Show LimitSettings instance Generic LimitSettings instance Datatype D1RLimits instance Constructor C1_0RLimits instance Selector S1_0_0RLimits instance Selector S1_0_1RLimits instance Selector S1_0_2RLimits instance Selector S1_0_3RLimits instance Selector S1_0_4RLimits instance Selector S1_0_5RLimits instance Selector S1_0_6RLimits instance Datatype D1LimitSettings instance Constructor C1_0LimitSettings instance Selector S1_0_0LimitSettings instance Selector S1_0_1LimitSettings instance Selector S1_0_2LimitSettings instance Selector S1_0_3LimitSettings instance Selector S1_0_4LimitSettings instance Selector S1_0_5LimitSettings instance Selector S1_0_6LimitSettings instance Datatype D1CUid instance Constructor C1_0CUid instance Datatype D1ResourceLimits instance Constructor C1_0ResourceLimits instance Selector S1_0_0ResourceLimits instance Selector S1_0_1ResourceLimits instance Datatype D1ResourceLimit instance Constructor C1_0ResourceLimit instance Constructor C1_1ResourceLimit instance Constructor C1_2ResourceLimit instance Default RLimits instance Default LimitSettings instance Serialize LimitSettings instance Serialize CUid instance Serialize RLimits instance Serialize ResourceLimits instance Serialize ResourceLimit -- | Worker can be in one of three states -- --
-- instance WorkerData IOWorker where -- type WData IOWorker = () -- type WMonad IOWorker = IO --data IOWorker -- | An exception type used by Protocol data ProtocolException -- | There has been an error during the conversion step ConversionException :: String -> ProtocolException -- | There has been an error while using the handler HandleException :: IOException -> ProtocolException -- | Check whether the worker is initialized initialized :: Worker a -> Bool instance Typeable1 Worker instance Typeable ProtocolException instance Generic CPid instance Show (Worker a) instance Eq (Worker a) instance Generic (Worker a) instance Show ProtocolException instance Datatype D1Worker instance Constructor C1_0Worker instance Selector S1_0_0Worker instance Selector S1_0_1Worker instance Selector S1_0_2Worker instance Selector S1_0_3Worker instance Datatype D1CPid instance Constructor C1_0CPid instance Exception ProtocolException instance WorkerData IOWorker instance Serialize (Worker a) instance Serialize CPid -- | A simple protocol for sending serializable data over handles -- -- Please note that this is a very simple implementation that works fine -- for most of that data, however, the size of the data you might send at -- one go is limited to MAX_WORD32 bytes. We use cereal for -- serialization. module System.Restricted.Worker.Protocol -- | Send some serialiazable data over a handle. Returns ByteString -- representing the encoded data. May throw ProtocolException sendData :: Serialize a => Handle -> a -> IO ByteString -- | Read the data from a handle and deserialize it. May throw -- ProtocolException getData :: Serialize a => Handle -> IO a -- | Safe version of getData that doesn't throw -- ProtocolException getDataSafe :: Serialize a => Handle -> IO (DecodeResult a) -- | Result of the deserialization type DecodeResult a = Either String a -- | An exception type used by Protocol data ProtocolException -- | There has been an error during the conversion step ConversionException :: String -> ProtocolException -- | There has been an error while using the handler HandleException :: IOException -> ProtocolException -- | The implementation of security restrictions module System.Restricted.Limits -- | Apply the LimitSettings setLimits :: LimitSettings -> IO () -- | Set rlimits using setrlimit syscall setRLimits :: RLimits -> IO () -- | Set the chroot jail chroot :: FilePath -> IO () -- | Change the uid of the current process changeUserID :: UserID -> IO () -- | Add a process to a cgroup setCGroup :: LimitSettings -> ProcessID -> IO () -- | Set the security context. To be more precise, it only sets up the -- type. Example usage: -- --
-- setupSELinuxCntx "my_restricted_t" --setupSELinuxCntx :: SecurityContext -> IO () -- | Waits for a certain period of time and then kills the process processTimeout :: ProcessID -> Int -> IO () -- | Library exposing internal functions uses by Worker useful work -- writing your own workers module System.Restricted.Worker.Internal -- | Kill a worker. Takes an initialized worker, returns non-initialized -- one. killWorker :: Worker a -> IO (Worker a) -- | Checks whether the worker is alive workerAlive :: Worker a -> IO Bool -- | Waits for a certain period of time and then kills the worker workerTimeout :: Worker a -> Int -> IO (Worker a) -- | Fork a worker process forkWorker :: Worker a -> Maybe (IO Handle) -> (Socket -> IO ()) -> IO ProcessID -- | Connect to the worker's socket and return a handle connectToWorker :: Worker a -> IO Handle -- | Create a new unix socket mkSock :: FilePath -> IO Socket -- | Remove a file if it exists. Should be thread-safe. removeFileIfExists :: FilePath -> IO () -- | Checks whether the process is alive hacky processAlive :: ProcessID -> IO Bool -- | A non-stripped pooling abstraction that restarts workers Some got has -- been taken from Pool by bos module System.Restricted.Worker.Pool -- | A simple pool for workers. Workers are restarted from time to time data WorkersPool w -- | Create a new workers pool mkPool :: MonadIO (WMonad a) => (Int -> WMonad a (Worker a, RestartWorker IO a)) -> Int -> Int -> WMonad a (WorkersPool a) -- | Like takeWorker + putWorker but takes care of the -- exception handling for you withWorker :: (MonadBaseControl IO m, MonadBase (WMonad a) m, MonadBaseControl IO (WMonad a), MonadIO (WMonad a)) => WorkersPool a -> ((Worker a, RestartWorker IO a) -> m b) -> m b -- | Take worker from the pool. The caller is responsible for putting the -- worker back into the pool or destroying it with destroyWorker takeWorker :: (MonadIO (WMonad a), MonadBaseControl IO (WMonad a)) => WorkersPool a -> WMonad a (Worker a, RestartWorker IO a) -- | Put the worker back in pool putWorker :: WorkersPool a -> (Worker a, RestartWorker IO a) -> IO () -- | Destroy a worker. Frees up space in the pool destroyWorker :: WorkersPool a -> Worker a -> IO () -- | Main entry point of the library module System.Restricted.Worker -- | Create an uninitialized worker mkDefaultWorker :: String -> FilePath -> LimitSettings -> Worker a -- | Start a general type of worker. -- -- The pre-forking action is a monadic action that will be run prior to -- calling forkWorker. It might be some initialization code, -- running the DB query, anything you want. The resulting WData -- will be passed to the callback. -- -- The socket that is passed to the callback is a server socket. startWorker :: (WorkerData w, MonadIO (WMonad w), MonadBase (WMonad w) m) => String -> FilePath -> Maybe (IO Handle) -> LimitSettings -> WMonad w (WData w) -> (WData w -> Socket -> IO ()) -> WMonad w (Worker w, RestartWorker m w) -- | Start a worker of type IOWorker The callback function is called -- every time a connectino is established -- --
-- >>> startIOWorker "test" "/tmp/test.sock" $ \h -> hPutStrLn h "hello, world" --startIOWorker :: String -> LimitSettings -> FilePath -> (Handle -> IO ()) -> IO (Worker IOWorker, RestartWorker IO IOWorker) -- | Kill a worker. Takes an initialized worker, returns non-initialized -- one. killWorker :: Worker a -> IO (Worker a) -- | Checks whether the worker is alive workerAlive :: Worker a -> IO Bool -- | Connect to the worker's socket and return a handle connectToWorker :: Worker a -> IO Handle