podenv-0.2.0: src/Podenv/Context.hs
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
-- makeLenses does not produce those
{-# OPTIONS_GHC -Wno-missing-signatures #-}
{-# OPTIONS_GHC -fno-warn-missing-export-lists #-}
-- | Runtime Context data types and lenses
module Podenv.Context where
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Lens.Family.TH (makeLenses)
import Podenv.Prelude
import System.Linux.Capabilities (Capability)
newtype ImageName = ImageName {unImageName :: Text}
deriving (Show)
data RuntimeContext
= Container ImageName
| Bubblewrap FilePath
deriving (Show)
data Mode = RO | RW
deriving (Show)
data VolumeType = HostPath FilePath | TmpFS | Volume Text
deriving (Show)
data Volume = MkVolume Mode VolumeType
deriving (Show)
data RunAs = RunAsRoot | RunAsHostUID | RunAsAnyUID
deriving (Show)
data Port = PortTcp Natural | PortUdp Natural
deriving (Show)
newtype Name = Name {unName :: Text}
deriving (Show)
-- | The application context to be executed by podman or kubectl
data Context = Context
{ -- | identifier
_name :: Name,
_namespace :: Maybe Text,
-- | container image name
_runtimeCtx :: RuntimeContext,
-- | network namespace name
_network :: Bool,
_ports :: [Port],
_runAs :: Maybe RunAs,
_selinux :: Bool,
-- | the unique uid for this container
_anyUid :: UserID,
-- | host uid
_uid :: UserID,
-- | container command
_command :: [Text],
_workdir :: Maybe FilePath,
-- | container env
_environ :: Map Text Text,
-- | container volumes
_mounts :: Map FilePath Volume,
_syscaps :: Set.Set Capability,
_ro :: Bool,
-- | container devices
_devices :: Set FilePath,
_hostname :: Maybe Text,
_interactive :: Bool,
_terminal :: Bool,
_privileged :: Bool
}
deriving (Show)
$(makeLenses ''Context)
defaultContext :: Name -> RuntimeContext -> Context
defaultContext _name _runtimeCtx =
Context
{ _name,
_runtimeCtx,
_command = [],
_uid = 0,
_namespace = Nothing,
-- todo keep track of fresh uid
_anyUid = 4242,
_selinux = True,
_network = False,
_ports = mempty,
_runAs = Nothing,
_environ = mempty,
_mounts = mempty,
_devices = mempty,
_syscaps = mempty,
-- TODO: make ro work for podman
_ro = True,
_workdir = Nothing,
_hostname = Nothing,
_interactive = False,
_terminal = False,
_privileged = False
}
rwHostPath :: FilePath -> Volume
rwHostPath = MkVolume RW . HostPath
roHostPath :: FilePath -> Volume
roHostPath = MkVolume RO . HostPath
tmpfs :: Volume
tmpfs = MkVolume RW TmpFS
-- Env and mounts head value takes priority
addEnv :: Text -> Text -> Context -> Context
addEnv k v = environ %~ Map.insertWith (\_n o -> o) k v
addMount :: FilePath -> Volume -> Context -> Context
addMount containerPath hostPath = mounts %~ Map.insertWith (\_n o -> o) containerPath hostPath
directMount :: FilePath -> Context -> Context
directMount fp = addMount fp (rwHostPath fp)
addDevice :: FilePath -> Context -> Context
addDevice dev = devices %~ Set.insert dev