src/Podman/Types.hs
is generated from a
Swagger[swagger API specification; the specifications for different Podman
API versions can be downloaded from some random Google Cloud Storage
bucket (because of course, what a totally obvious place to put
your important specifications).
podman-codegen
is the program that does the
code generation, and there's a (Stack-only) script to run it:
regenerate-podman-types.sh
.
See the script for more details -- to get a pretty version of the
generated code, you need Ormolu, HLint and Refactor installed,
but you can comment those bits out if you want it to run quicker
and don't care about the code formatting.
See also the GitHub Actions workflows under .github/workflows
for examples of installing those tools and running the script.
Sometimes you might be able to switch between versions of a Swagger file
with no changes to podman-codegen
, but more often, you'll need to
update it to take account of changes.
Note that the "smart constructors" like mkSpecGenerator
have the
number of arguments they take hard-coded (rather than getting this
information from the Swagger specification) - fiddle with the
numbers around line 618 of the renderCtor
function
until the generated code compiles. (NB that too many arguments
is a better error to have than too few, because ghc
will tell
you in its error messages how many arguments you should have had.)
The Podman server implementation treats many arguments as optional,
which means that we can just skip generating code for datatypes
we find problematic for any reason. The skipTypes
function handles that.
Podman's main API documentation page (generated from the same
Swagger specification as src/Podman/Types.hs
) is at
https://docs.podman.io/en/latest/_static/api.html. Apparently
it's hosted by Read the Docs, but inexplicably omits
the standard (and very useful) Read the Docs feature of being able
to select historical versions of the documentation.
Instead, pick the version of the Podman library you're interested in, take a guess at what URL it might be at (e.g. http://docs.podman.io/en/v3.0.1/_static/api-static.html), and see if it works.
(Actually, there is another way -- go to https://readthedocs.org/projects/podman/, click through to the version you're interested in, and look for a link near the bottom of the page to "our API documentation Reference".)
You can start podman running as a server on a free TCP port by running e.g.
$ podman --log-level=debug system service --time=0 tcp:0.0.0.0:3000
(Or you could use a Unix domain socket to listen on -- see the Podman docco on how to do that.)
YMMV, but I found running a server from Ubuntu a bit flaky -- I
had more replicable results running the server on
Alpine Linux version 3.14, which has podman
version 3.2.3
in its repositories. You may as well install
podman-remote
and podman-rc
(which contains an /etc/init.d
service for root-ful podan) as well.
Probably, you could run the server out of a Docker container, but I created a Vagrant libvirt box with podman installed (see here), which might be useful.
If you want to inspect what's being sent between client and server, HTTP is much easier to eavesdrop on than Unix domain sockets.
Some options:
-
Interpose
mitmproxy
as a reverse proxy in front of the actual server.This is fairly straightforward. Assuming you've got Python 3 installed (I haven't tried Python 2), install
mitmproxy
with$ pip install mitmproxy
and ensure
~/.local/bin
is on your PATH.Let's suppose podman is being served on port 3000. To run a reverse proxy on port 3001 (plus a web UI on port 8080), run
$ mitmweb --web-port 8080 \ --listen-host 0.0.0.0 --listen-port 3001 \ --mode reverse:http://localhost:3000
But note that
mitmproxy
doesn't handle the TCP streams from acontainer attach
command well -- that seemed to cause errors in the web UI. -
Run
wireshark
(ortcpdump
) to capture the traffic and then inspect it.
Note that the Podman command-line tool uses an odd and not terribly consistent syntax for specifying server URLs.
If you're running a server, you use a URL of the format
tcp:127.0.0.1:3000
; e.g.
$ podman system service --time=0 tcp:0.0.0.0:3000
But if you're connecting to a server using podman-remote
,
you need forward slashes after the "tcp
":
$ podman-remote --url tcp://localhost:3000/ ps -a
And this Haskell library uses neither of those -- it uses
plain old HTTP URLs -- e.g. http://localhost:300/
.
(And of course you can also serve on or connect to Unix domain sockets, but I tend to use TCP sockets, since the software I'm developing runs the Podman server on a different host to the client.)