podman- A podman remote client library
Safe HaskellSafe-Inferred



The podman library provides a simple interface for interacting with a podman API. Use this library to validate the API and integrate podman in Haskell applications.

This tutorial introduces how to use the podman library to write Haskell scripts.

In another terminal, ensure the API is running:

$ podman --log-level=debug system service --time=0 /var/run/podman.sock


    To start using this library you need a haskell toolchain, on fedora run:

    $ sudo dnf install -y ghc cabal-install && cabal update

    Then get a copy of the library by running:

    $ git clone https://github.com/softwarefactory-project/podman-haskell
    $ cd podman-haskell

    Install the library by running:

    $ cabal install --lib podman

    Validate the library is correctly installed by running:

    $ ghci
    Prelude> import Podman
    Prelude Podman> :set prompt "> "
    > :set -XOverloadedStrings
    > withClient "http+unix://var/run/podman.sock" getVersion
    Right (Version {_versionApiVersion = "1.40", _versionVersion = "3.1.0-dev"})

    Create the client

    Most functions require an existing PodmanClient which carries the endpoint url and the http client manager.

    The only way to get the client is through the withClient function, which uses a callback function. To make this easier to use in ghci, create this helper:

    > let c = withClient "http+unix://var/run/podman.sock"
    > c $ \client -> getVersion client

    Call endpoint

    API functions operate with Haskell record, e.g.: InspectContainerResponse. Each field is a function that can be used with the record:

    > :type _inspectContainerResponseImageName
    _inspectContainerResponseImageName :: InspectContainerResponse -> Text

    For example, to inspect a container named "podman-demo", use containerInspect:

    > Right res <- c $ \client -> containerInspect client (ContainerName "podman-demo") False
    > :t res
    res :: InspectContainerResponse
    > _inspectContainerResponseImageName res

    When an API endpoint has complex arguments, the library function also use records:

    Then the default fields can be modified using the record update syntax:

    > let myListQuery = defaultContainerListQuery { _containerListQueryall = Just True }
    > c $ \client -> containerList client myListQuery
    Right [ListContainer {...}, ...]

    The field name can be used in a mapping function, for example, to get the name of all the containers:

    > (fmap . fmap . fmap $ _listContainerNames) <$> c $ \client -> containerList client myListQuery
    Right ["podman-demo", "rootless-cni-infra", "..."]

    Note that we use multiple fmap to penetrate each layer, e.g. MonadIO, Result, and List.

    Copy files

    The send and get files expect tar files, so first import the library and define a utility function:

    > import qualified Codec.Archive.Tar as Tar
    > import qualified Codec.Archive.Tar.Entry as Tar
    > let tar = mapM (\(path, content) -> Tar.fileEntry <$> Tar.toTarPath False path <*> pure content)

    Send files with containerSendFiles:

    > let Right tarball = tar [("test.dat", "test-content")]
    > c $ \client -> containerSendFiles client (ContainerName "demo-haskell") tarball "/tmp/test" Nothing

    Get files with containerGetFiles:

    > c $ \client -> containerGetFiles client (ContainerName "demo-haskell") "/tmp/test"
    Right (Next (Entry {entryTarPath = "test", entryContent = Directory, ..}))

    Use interactive session

    The interactive functions expect a callback, for example, to get a container log with containerLogs:

    > c $ \client -> containerLogs client (ContainerName "demo-haskell") LogBoth (defaultLogsQuery {_logsQueryfollow = Just follow}) print
    Stdout "container output"
    Stdout "..."

    The containerAttach function provides a ContainerConnection handler that can be used to read and write. Checkout the podman-demo script for more detailed examples.