diff options
32 files changed, 732 insertions, 76 deletions
diff --git a/.cirrus.yml b/.cirrus.yml index 91e94dd47..964368743 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -417,8 +417,6 @@ testing_task: gce_instance: image_name: "${PRIOR_UBUNTU_CACHE_IMAGE_NAME}" - timeout_in: 120m - env: ADD_SECOND_PARTITION: 'true' matrix: @@ -473,8 +471,6 @@ special_testing_rootless_task: - RCLI: 'true' - RCLI: 'false' - timeout_in: 60m - networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} | ${LOGFORMAT} integration_test' @@ -515,8 +511,6 @@ special_testing_in_podman_task: MOD_CONTAINERS_CONF: 'false' # Use existing/native setup SPECIALMODE: 'in_podman' # See docs - timeout_in: 60m - networking_script: '${CIRRUS_WORKING_DIR}/${SCRIPT_BASE}/networking.sh' setup_environment_script: '$SCRIPT_BASE/setup_environment.sh |& ${TIMESTAMP}' integration_test_script: '$SCRIPT_BASE/integration_test.sh |& ${TIMESTAMP} | ${LOGFORMAT} integration_test' diff --git a/cmd/podman/common/volumes.go b/cmd/podman/common/volumes.go index 20c31bd81..ca0b10765 100644 --- a/cmd/podman/common/volumes.go +++ b/cmd/podman/common/volumes.go @@ -88,17 +88,11 @@ func parseVolumes(volumeFlag, mountFlag, tmpfsFlag []string, addReadOnlyTmpfs bo if _, ok := unifiedVolumes[dest]; ok { continue } - localOpts := options - if dest == "/run" { - localOpts = append(localOpts, "noexec", "size=65536k") - } else { - localOpts = append(localOpts, "exec") - } unifiedMounts[dest] = spec.Mount{ Destination: dest, Type: TypeTmpfs, Source: "tmpfs", - Options: localOpts, + Options: options, } } } diff --git a/cmd/podman/containers/create.go b/cmd/podman/containers/create.go index 6eec93f98..801547033 100644 --- a/cmd/podman/containers/create.go +++ b/cmd/podman/containers/create.go @@ -297,7 +297,12 @@ func createPodIfNecessary(s *specgen.SpecGenerator, netOpts *entities.NetOptions Infra: true, Net: netOpts, CreateCommand: os.Args, + Hostname: s.ContainerBasicConfig.Hostname, } + // Unset config values we passed to the pod to prevent them being used twice for the container and pod. + s.ContainerBasicConfig.Hostname = "" + s.ContainerNetworkConfig = specgen.ContainerNetworkConfig{} + s.Pod = podName return registry.ContainerEngine().PodCreate(context.Background(), createOptions) } diff --git a/cmd/podman/early_init_linux.go b/cmd/podman/early_init_linux.go index e2893ff69..4e232a0b0 100644 --- a/cmd/podman/early_init_linux.go +++ b/cmd/podman/early_init_linux.go @@ -32,7 +32,7 @@ func setUMask() { func earlyInitHook() { if err := setRLimits(); err != nil { - fmt.Fprint(os.Stderr, "Failed to set rlimits: "+err.Error()) + fmt.Fprintf(os.Stderr, "Failed to set rlimits: %s\n", err.Error()) } setUMask() diff --git a/cmd/podman/root.go b/cmd/podman/root.go index dd9c75ece..8f77e5893 100644 --- a/cmd/podman/root.go +++ b/cmd/podman/root.go @@ -111,6 +111,30 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error { cfg := registry.PodmanConfig() + // --connection is not as "special" as --remote so we can wait and process it here + var connErr error + conn := cmd.Root().LocalFlags().Lookup("connection") + if conn != nil && conn.Changed { + cfg.Engine.ActiveService = conn.Value.String() + + var err error + cfg.URI, cfg.Identity, err = cfg.ActiveDestination() + if err != nil { + connErr = errors.Wrap(err, "failed to resolve active destination") + } + + if err := cmd.Root().LocalFlags().Set("url", cfg.URI); err != nil { + connErr = errors.Wrap(err, "failed to override --url flag") + } + + if err := cmd.Root().LocalFlags().Set("identity", cfg.Identity); err != nil { + connErr = errors.Wrap(err, "failed to override --identity flag") + } + } + if connErr != nil { + return connErr + } + // Prep the engines if _, err := registry.NewImageEngine(cmd, args); err != nil { return err @@ -226,10 +250,11 @@ func loggingHook() { func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { cfg := opts.Config - uri, ident := resolveDestination() + srv, uri, ident := resolveDestination() lFlags := cmd.Flags() lFlags.BoolVarP(&opts.Remote, "remote", "r", false, "Access remote Podman service (default false)") + lFlags.StringVarP(&opts.Engine.ActiveService, "connection", "c", srv, "Connection to use for remote Podman service") lFlags.StringVar(&opts.URI, "url", uri, "URL to access Podman service (CONTAINER_HOST)") lFlags.StringVar(&opts.Identity, "identity", ident, "path to SSH identity file, (CONTAINER_SSHKEY)") @@ -279,24 +304,24 @@ func rootFlags(cmd *cobra.Command, opts *entities.PodmanConfig) { } } -func resolveDestination() (string, string) { +func resolveDestination() (string, string, string) { if uri, found := os.LookupEnv("CONTAINER_HOST"); found { var ident string if v, found := os.LookupEnv("CONTAINER_SSHKEY"); found { ident = v } - return uri, ident + return "", uri, ident } cfg, err := config.ReadCustomConfig() if err != nil { logrus.Warning(errors.Wrap(err, "unable to read local containers.conf")) - return registry.DefaultAPIAddress(), "" + return "", registry.DefaultAPIAddress(), "" } uri, ident, err := cfg.ActiveDestination() if err != nil { - return registry.DefaultAPIAddress(), "" + return "", registry.DefaultAPIAddress(), "" } - return uri, ident + return cfg.Engine.ActiveService, uri, ident } diff --git a/cmd/podman/system/connection/add.go b/cmd/podman/system/connection/add.go index af13b970c..8b9ab6dbb 100644 --- a/cmd/podman/system/connection/add.go +++ b/cmd/podman/system/connection/add.go @@ -95,7 +95,7 @@ func add(cmd *cobra.Command, args []string) error { uri.Host = net.JoinHostPort(uri.Hostname(), cmd.Flag("port").DefValue) } - if uri.Path == "" { + if uri.Path == "" || uri.Path == "/" { if uri.Path, err = getUDS(cmd, uri); err != nil { return errors.Wrapf(err, "failed to connect to %q", uri.String()) } diff --git a/completions/bash/podman b/completions/bash/podman index f0c8e7394..379ba7fc8 100644 --- a/completions/bash/podman +++ b/completions/bash/podman @@ -3602,22 +3602,32 @@ _podman_volume() { _podman_podman() { local options_with_args=" - --config -c + --cni-config-dir + --conmon + --connection -c + --events-backend + --hooks-dir + --identity + --log-level + --namespace + --network-cmd-path --root --runroot --storage-driver --storage-opt - --log-level - --namespace - " + --tmpdir + --runtime + --url + " local boolean_options=" --help - -h + --syslog --version + -h + -r, --remote -v - --syslog " - commands=" + commands=" attach auto-update build diff --git a/docs/source/Tutorials.rst b/docs/source/Tutorials.rst index 1b17bc4c7..33e4ae3d3 100644 --- a/docs/source/Tutorials.rst +++ b/docs/source/Tutorials.rst @@ -10,3 +10,4 @@ Here are a number of useful tutorials to get you up and running with Podman. If * `How to sign and distribute container images using Podman <https://github.com/containers/podman/blob/master/docs/tutorials/image_signing.md>`_: Learn how to setup and use image signing with Podman. * `Podman remote-client tutorial <https://github.com/containers/podman/blob/master/docs/tutorials/remote_client.md>`_: A brief how-to on using the Podman remote-client. * `How to use libpod for custom/derivative projects <https://github.com/containers/podman/blob/master/docs/tutorials/podman-derivative-api.md>`_: How the libpod API can be used within your own project. +* `How to use Podman's Go bindings <https://github.com/containers/podman/blob/master/docs/tutorials/podman-go-bindings.md>`_: A brief how-to on using Podman's Go bindings in external applications. diff --git a/docs/source/markdown/podman-remote.1.md b/docs/source/markdown/podman-remote.1.md index 0d7be1e5d..23ccaf0e6 100644 --- a/docs/source/markdown/podman-remote.1.md +++ b/docs/source/markdown/podman-remote.1.md @@ -23,7 +23,7 @@ Podman-remote provides a local client interacting with a Podman backend node thr ## GLOBAL OPTIONS -**--connection**=*name* +**--connection**=*name*, **-c** Remote connection name diff --git a/docs/source/markdown/podman.1.md b/docs/source/markdown/podman.1.md index 16439c167..c53da6b5f 100644 --- a/docs/source/markdown/podman.1.md +++ b/docs/source/markdown/podman.1.md @@ -31,6 +31,9 @@ Note: CGroup manager is not supported in rootless mode when using CGroups Versio **--cni-config-dir** Path of the configuration directory for CNI networks. (Default: `/etc/cni/net.d`) +**--connection**, **-c** +Connection to use for remote podman (Default connection is configured in `containers.conf`) + **--conmon** Path of the conmon binary (Default path is configured in `containers.conf`) diff --git a/docs/tutorials/README.md b/docs/tutorials/README.md index 191d7a4b5..4beb069ac 100644 --- a/docs/tutorials/README.md +++ b/docs/tutorials/README.md @@ -27,3 +27,7 @@ How the libpod API can be used within your own project. **[Image Signing](image_signing.md)** Learn how to setup and use image signing with Podman. + +**[Go Bindings](podman-go-bindings.md)** + +A brief how-to on using Podman's Go bindings in external applications. diff --git a/docs/tutorials/podman-go-bindings.md b/docs/tutorials/podman-go-bindings.md new file mode 100644 index 000000000..ddebf7e99 --- /dev/null +++ b/docs/tutorials/podman-go-bindings.md @@ -0,0 +1,546 @@ +![PODMAN logo](../../logo/podman-logo-source.svg) + +# Podman Go bindings + +## Introduction + +In the release of Podman 2.0, we removed the experimental tag +from its recently introduced RESTful service. While it might +be interesting to interact with a RESTFul server using curl, +using a set of Go based bindings is probably a more direct +route to a production ready application. Let’s take a look +at how easily that can be accomplished. + +If you haven't yet, [install Go](https://golang.org/doc/install). + +Be careful to double-check that the version of golang is new +enough (i.e. `go version`), version 1.13.x or higher is +supported. If needed, Go sources and binaries can be fetched +from the [official Go website](https://golang.org/dl/). + +The Podman Go bindings are a set of functions to allow +developers to execute Podman operations from within their Go +based application. The Go bindings connect to a Podman service +which can run locally or on a remote machine. You can perform +many operations including pulling and listing images, starting, +stopping or inspecting containers. Currently, the Podman +repository has bindings available for operations on images, +containers, pods, networks and manifests among others. The +bindings are available on the [v2.0 branch in the +upstream Podman repository](https://github.com/containers/podman/tree/v2.0). +You can fetch the bindings for your application using Go modules: + +```bash +$ cd $HOME +$ mkdir example && cd example +$ go mod init example.com +go: creating new go.mod: module example.com +$ go get github.com/containers/podman/v2@v2.0.4 +go: downloading github.com/containers/podman/v2 v2.0.4 +go get: github.com/containers/podman/v2@v2.0.4: parsing go.mod: + module declares its path as: github.com/containers/libpod/v2 + but was required as: github.com/containers/podman/v2 +``` + +This creates a new `go.mod` file in the current directory that looks as follows: + +```bash +module example.com + +go 1.14 + +require github.com/containers/libpod/v2 v2.0.4 // indirect +``` + +You can also try a demo application with the Go modules created already: + +```bash +$ git clone https://github.com/containers/Demos +$ cd Demos/podman_go_bindings +$ ls +README.md go.mod go.sum main.go +``` + + +## How do I use them + +In this tutorial, you will learn through basic examples how to: + +0. [Start the Podman system service](#start-service) +1. [Connect to the Podman system service](#connect-service) +2. [Pull images](#pull-images) +3. [List images](#list-images) +4. [Create and start a container from an image](#create-start-container) +5. [List containers](#list-containers) +6. [Inspect the container](#inspect-container) +7. [Stop the container](#stop-container) +8. [Debugging tips](#debugging-tips) + + +### Start the Podman system service <a name="start-service"></a> +The recommended way to start Podman system service in production mode +is via systemd socket-activation: + +```bash +$ systemctl --user start podman.socket +``` + +There’s no timeout specified when starting the system service via socket-activation. + +For purposes of this demo, we will start the service using the Podman +command itself. If you prefer the system service to timeout after, say, +5000 seconds, you can run it like so: + +```bash +$ podman system service -t 5000 +``` + +Note that the 5000 seconds uptime is refreshed after every command is received. +If you want the service to stay up until the machine is shutdown or the process +is terminated, use `0` (zero) instead of 5000. For this demo, we will use no timeout: + +```bash +$ podman system service -t 0 +``` + + +Open another terminal window and check if the Podman socket exists: + +```bash +$ ls /run/user/${UID}/podman +podman.sock +``` + +If you’re running the system service as root, podman.sock will be found in /run/podman: +```bash +# ls /run/podman +podman.sock +``` + + +### Connect to the Podman system service <a name="connect-service"></a> +First, you need to create a connection that connects to the system service. +The critical piece of information for setting up a new connection is the endpoint. +The endpoint comes in the form of an URI (method:/path/to/socket). For example, +to connect to the local rootful socket the URI would be `unix:/run/podman/podman.sock` +and for a rootless user it would be `unix:$(XDG_RUNTIME_DIR)/podman/podman.sock`, +typically: `unix:/run/user/${UID}/podman/podman.sock`. + + +The following Go example snippet shows how to set up a connection for a rootless user. +```Go +package main + +import ( + "context" + "fmt" + "os" + + "github.com/containers/libpod/v2/libpod/define" + "github.com/containers/libpod/v2/pkg/bindings" + "github.com/containers/libpod/v2/pkg/bindings/containers" + "github.com/containers/libpod/v2/pkg/bindings/images" + "github.com/containers/libpod/v2/pkg/domain/entities" + "github.com/containers/libpod/v2/pkg/specgen" +) + +func main() { + fmt.Println("Welcome to the Podman Go bindings tutorial") + + // Get Podman socket location + sock_dir := os.Getenv("XDG_RUNTIME_DIR") + socket := "unix:" + sock_dir + "/podman/podman.sock" + + // Connect to Podman socket + connText, err := bindings.NewConnection(context.Background(), socket) + if err != nil { + fmt.Println(err) + os.Exit(1) + } +} +``` + +The `connText` variable received from the NewConnection function is of type +context.Context(). In subsequent uses of the bindings, you will use this context +to direct the bindings to your connection. This can be seen in the examples below. + +### Pull an image <a name="pull-images"></a> + +Next, we will pull a couple of images using the images.Pull() binding. +This binding takes three arguments: + - The context variable created by the bindings.NewConnection() call in the first example + - The image name + - Options for image pull + +**Append the following lines to your function:** + +```Go + // Pull Busybox image (Sample 1) + fmt.Println("Pulling Busybox image...") + _, err = images.Pull(connText, "docker.io/busybox", entities.ImagePullOptions{}) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Pull Fedora image (Sample 2) + rawImage := "registry.fedoraproject.org/fedora:latest" + fmt.Println("Pulling Fedora image...") + _, err = images.Pull(connText, rawImage, entities.ImagePullOptions{}) + if err != nil { + fmt.Println(err) + os.Exit(1) + } +``` + +**Run it:** + +```bash +$ go run main.go +Welcome to the Podman Go bindings tutorial +Pulling Busybox image... +Pulling Fedora image... +$ +``` + +The system service side should echo messages like so: + +```bash +Trying to pull docker.io/busybox... +Getting image source signatures +Copying blob 61c5ed1cbdf8 [--------------------------------------] 0.0b / 0.0b +Copying config 018c9d7b79 done +Writing manifest to image destination +Storing signatures +Trying to pull registry.fedoraproject.org/fedora:latest... +Getting image source signatures +Copying blob dd9f43919ba0 [--------------------------------------] 0.0b / 0.0b +Copying config 00ff39a8bf done +Writing manifest to image destination +Storing signatures +``` + + +### List images <a name="list-images"></a> +Next, we will pull an image using the images.List() binding. +This binding takes three arguments: + - The context variable created earlier + - An optional bool 'all' + - An optional map of filters + +**Append the following lines to your function:** + +```Go + // List images + imageSummary, err := images.List(connText, nil, nil) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + var names []string + for _, i := range imageSummary { + names = append(names, i.RepoTags...) + } + fmt.Println("Listing images...") + fmt.Println(names) +``` + +**Run it:** + +```bash +$ go run main.go +Welcome to the Podman Go bindings tutorial +Pulling Busybox image... +Pulling Fedora image... +Listing images... +[docker.io/library/busybox:latest registry.fedoraproject.org/fedora:latest] +$ +``` + + +### Create and Start a Container from an Image <a name="create-start-container"></a> + +To create the container spec, we use specgen.NewSpecGenerator() followed by +calling containers.CreateWithSpec() to actually create a new container. +specgen.NewSpecGenerator() takes 2 arguments: + - name of the image + - whether it's a rootfs + +containers.CreateWithSpec() takes 2 arguments: + - the context created earlier + - the spec created by NewSpecGenerator + +Next, the container is actually started using the containers.Start() binding. +containers.Start() takes three arguments: + - the context + - the name or ID of the container created + - an optional parameter for detach keys + +After the container is started, it's a good idea to ensure the container is +in a running state before you proceed with further operations. +The containers.Wait() takes care of that. +containers.Wait() takes three arguments: + - the context + - the name or ID of the container created + - container state (running/paused/stopped) + +**Append the following lines to your function:** + +```Go + // Container create + s := specgen.NewSpecGenerator(rawImage, false) + s.Terminal = true + r, err := containers.CreateWithSpec(connText, s) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + // Container start + fmt.Println("Starting Fedora container...") + err = containers.Start(connText, r.ID, nil) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + + running := define.ContainerStateRunning + _, err = containers.Wait(connText, r.ID, &running) + if err != nil { + fmt.Println(err) + os.Exit(1) + } +``` + +**Run it:** + +```bash +$ go run main.go +Welcome to the Podman Go bindings tutorial +Pulling image... +Starting Fedora container... +$ +``` + +Check if the container is running: + +```bash +$ podman ps +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +665831d31e90 registry.fedoraproject.org/fedora:latest /bin/bash Less than a second ago Up Less than a second ago dazzling_mclean +$ +``` + + +### List Containers <a name="list-containers"></a> + +Containers can be listed using the containers.List() binding. +containers.List() takes seven arguments: + - the context + - output filters + - boolean to show all containers, by default only running containers are listed + - number of latest created containers, all states (running/paused/stopped) + - boolean to print pod information + - boolean to print rootfs size + - boolean to print oci runtime and container state + +**Append the following lines to your function:** + +```Go + // Container list + var latestContainers = 1 + containerLatestList, err := containers.List(connText, nil, nil, &latestContainers, nil, nil, nil) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + fmt.Printf("Latest container is %s\n", containerLatestList[0].Names[0]) +``` + +**Run it:** + +```bash +$ go run main.go +Welcome to the Podman Go bindings tutorial +Pulling Busybox image... +Pulling Fedora image... +Listing images... +[docker.io/library/busybox:latest registry.fedoraproject.org/fedora:latest] +Starting Fedora container... +Latest container is dazzling_mclean +$ +``` + + +### Inspect Container <a name="inspect-container"></a> +Containers can be inspected using the containers.Inspect() binding. +containers.Inspect() takes 3 arguments: + - context + - image name or ID + - optional boolean to check for container size + + +**Append the following lines to your function:** + +```Go + // Container inspect + ctrData, err := containers.Inspect(connText, r.ID, nil) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + fmt.Printf("Container uses image %s\n", ctrData.ImageName) + fmt.Printf("Container running status is %s\n", ctrData.State.Status) +``` + +**Run it:** + +```bash +$ go run main.go +Welcome to the Podman Go bindings tutorial +Pulling Busybox image... +Pulling Fedora image... +Listing images... +[docker.io/library/busybox:latest registry.fedoraproject.org/fedora:latest] +Starting Fedora container... +Latest container is peaceful_noether +Fedora Container uses image registry.fedoraproject.org/fedora:latest +Fedora Container running status is running +$ +``` + + +### Stop Container <a name="stop-container"></a> + +A container can be stopped by the containers.Stop() binding. +containers.Stop() takes 3 arguments: + - context + - image name or ID + - optional timeout + +**Append the following lines to your function:** + +```Go + // Container stop + fmt.Println("Stopping the container...") + err = containers.Stop(connText, r.ID, nil) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + ctrData, err = containers.Inspect(connText, r.ID, nil) + if err != nil { + fmt.Println(err) + os.Exit(1) + } + fmt.Printf("Container running status is now %s\n", ctrData.State.Status) +``` + +**Run it:** + +```bash +$ go run main.go +Welcome to the Podman Go bindings tutorial +Pulling Busybox image... +Pulling Fedora image... +Listing images... +[docker.io/library/busybox:latest registry.fedoraproject.org/fedora:latest] +Starting Fedora container... +Latest container is peaceful_noether +Fedora Container uses image registry.fedoraproject.org/fedora:latest +Fedora Container running status is running +Stopping Fedora container... +Container running status is now exited +``` + + +### Debugging tips <a name="debugging-tips"></a> + +To debug in a development setup, you can start the Podman system service +in debug mode like so: + +```bash +$ podman --log-level=debug system service -t 0 +``` + +The `--log-level=debug` echoes all the logged requests and is useful to +trace the execution path at a finer granularity. A snippet of a sample run looks like: + +```bash +INFO[0000] podman filtering at log level debug +DEBU[0000] Called service.PersistentPreRunE(podman --log-level=debug system service -t0) +DEBU[0000] Ignoring libpod.conf EventsLogger setting "/home/lsm5/.config/containers/containers.conf". Use "journald" if you want to change this setting and remove libpod.conf files. +DEBU[0000] Reading configuration file "/usr/share/containers/containers.conf" +DEBU[0000] Merged system config "/usr/share/containers/containers.conf": {Editors note: the remainder of this line was removed due to Jekyll formatting errors.} +DEBU[0000] Using conmon: "/usr/bin/conmon" +DEBU[0000] Initializing boltdb state at /home/lsm5/.local/share/containers/storage/libpod/bolt_state.db +DEBU[0000] Overriding run root "/run/user/1000/containers" with "/run/user/1000" from database +DEBU[0000] Using graph driver overlay +DEBU[0000] Using graph root /home/lsm5/.local/share/containers/storage +DEBU[0000] Using run root /run/user/1000 +DEBU[0000] Using static dir /home/lsm5/.local/share/containers/storage/libpod +DEBU[0000] Using tmp dir /run/user/1000/libpod/tmp +DEBU[0000] Using volume path /home/lsm5/.local/share/containers/storage/volumes +DEBU[0000] Set libpod namespace to "" +DEBU[0000] Not configuring container store +DEBU[0000] Initializing event backend file +DEBU[0000] using runtime "/usr/bin/runc" +DEBU[0000] using runtime "/usr/bin/crun" +WARN[0000] Error initializing configured OCI runtime kata: no valid executable found for OCI runtime kata: invalid argument +DEBU[0000] using runtime "/usr/bin/crun" +INFO[0000] Setting parallel job count to 25 +INFO[0000] podman filtering at log level debug +DEBU[0000] Called service.PersistentPreRunE(podman --log-level=debug system service -t0) +DEBU[0000] Ignoring libpod.conf EventsLogger setting "/home/lsm5/.config/containers/containers.conf". Use "journald" if you want to change this setting and remove libpod.conf files. +DEBU[0000] Reading configuration file "/usr/share/containers/containers.conf" +``` + +If the Podman system service has been started via systemd socket activation, +you can view the logs using journalctl. The logs after a sample run look like so: + +```bash +$ journalctl --user --no-pager -u podman.socket +-- Reboot -- +Jul 22 13:50:40 nagato.nanadai.me systemd[1048]: Listening on Podman API Socket. +$ +``` + +```bash +$ journalctl --user --no-pager -u podman.service +Jul 22 13:50:53 nagato.nanadai.me systemd[1048]: Starting Podman API Service... +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 38480630a8bdaa3e1a0ebd34c94038591b0d7ad994b37be5b4f2072bb6ef0879: error acquiring lock 0 for volume 38480630a8bdaa3e1a0ebd34c94038591b0d7ad994b37be5b4f2072bb6ef0879: file exists" +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 47d410af4d762a0cc456a89e58f759937146fa3be32b5e95a698a1d4069f4024: error acquiring lock 0 for volume 47d410af4d762a0cc456a89e58f759937146fa3be32b5e95a698a1d4069f4024: file exists" +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 86e73f082e344dad38c8792fb86b2017c4f133f2a8db87f239d1d28a78cf0868: error acquiring lock 0 for volume 86e73f082e344dad38c8792fb86b2017c4f133f2a8db87f239d1d28a78cf0868: file exists" +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume 9a16ea764be490a5563e384d9074ab0495e4d9119be380c664037d6cf1215631: error acquiring lock 0 for volume 9a16ea764be490a5563e384d9074ab0495e4d9119be380c664037d6cf1215631: file exists" +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume bfd6b2a97217f8655add13e0ad3f6b8e1c79bc1519b7a1e15361a107ccf57fc0: error acquiring lock 0 for volume bfd6b2a97217f8655add13e0ad3f6b8e1c79bc1519b7a1e15361a107ccf57fc0: file exists" +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: time="2020-07-22T13:50:54-04:00" level=error msg="Error refreshing volume f9b9f630982452ebcbed24bd229b142fbeecd5d4c85791fca440b21d56fef563: error acquiring lock 0 for volume f9b9f630982452ebcbed24bd229b142fbeecd5d4c85791fca440b21d56fef563: file exists" +Jul 22 13:50:54 nagato.nanadai.me podman[1527]: Trying to pull registry.fedoraproject.org/fedora:latest... +Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Getting image source signatures +Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Copying blob sha256:dd9f43919ba05f05d4f783c31e83e5e776c4f5d29dd72b9ec5056b9576c10053 +Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Copying config sha256:00ff39a8bf19f810a7e641f7eb3ddc47635913a19c4996debd91fafb6b379069 +Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Writing manifest to image destination +Jul 22 13:50:55 nagato.nanadai.me podman[1527]: Storing signatures +Jul 22 13:50:55 nagato.nanadai.me systemd[1048]: podman.service: unit configures an IP firewall, but not running as root. +Jul 22 13:50:55 nagato.nanadai.me systemd[1048]: (This warning is only shown for the first unit using IP firewalling.) +Jul 22 13:51:15 nagato.nanadai.me systemd[1048]: podman.service: Succeeded. +Jul 22 13:51:15 nagato.nanadai.me systemd[1048]: Finished Podman API Service. +Jul 22 13:51:15 nagato.nanadai.me systemd[1048]: podman.service: Consumed 1.339s CPU time. +$ +``` + + +## Wrap Up +Podman v2 provides a set of Go bindings to allow developers to integrate Podman +functionality conveniently in their Go application. These Go bindings require +the Podman system service to be running in the background and this can easily +be achieved using systemd socket activation. Once set up, you are able to use a +set of Go based bindings to create, maintain and monitor your container images, +containers and pods in a way which fits very nicely in many production environments. + + +## References +- Podman v2 is available for most major distributions along with MacOS and Windows. +Installation details are available on the [Podman official website](https://podman.io/getting-started/). + +- Documentation can be found at the [Podman Docs page](https://docs.podman.io). +It also includes a section on the [RESTful API](https://docs.podman.io/en/latest/Reference.html). @@ -13,7 +13,7 @@ require ( github.com/containers/buildah v1.15.1-0.20200731151214-29f4d01c621c github.com/containers/common v0.18.0 github.com/containers/conmon v2.0.19+incompatible - github.com/containers/image/v5 v5.5.1 + github.com/containers/image/v5 v5.5.2 github.com/containers/psgo v1.5.1 github.com/containers/storage v1.23.0 github.com/coreos/go-systemd/v22 v22.1.0 @@ -79,6 +79,8 @@ github.com/containers/conmon v2.0.19+incompatible h1:1bDVRvHy2MUNTUT/SW6LlHsJHQB github.com/containers/conmon v2.0.19+incompatible/go.mod h1:hgwZ2mtuDrppv78a/cOBNiCm6O0UMWGx1mu7P00nu5I= github.com/containers/image/v5 v5.5.1 h1:h1FCOXH6Ux9/p/E4rndsQOC4yAdRU0msRTfLVeQ7FDQ= github.com/containers/image/v5 v5.5.1/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM= +github.com/containers/image/v5 v5.5.2 h1:fv7FArz0zUnjH0W0l8t90CqWFlFcQrPP6Pug+9dUtVI= +github.com/containers/image/v5 v5.5.2/go.mod h1:4PyNYR0nwlGq/ybVJD9hWlhmIsNra4Q8uOQX2s6E2uM= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b h1:Q8ePgVfHDplZ7U33NwHZkrVELsZP5fYj9pM5WBZB2GE= github.com/containers/libtrust v0.0.0-20190913040956-14b96171aa3b/go.mod h1:9rfv8iPl1ZP7aqh9YA68wnZv2NUDbXdcdPHVz0pFbPY= github.com/containers/ocicrypt v1.0.2/go.mod h1:nsOhbP19flrX6rE7ieGFvBlr7modwmNjsqWarIUce4M= diff --git a/libpod/container_internal_linux.go b/libpod/container_internal_linux.go index fdee3877c..ea4340e00 100644 --- a/libpod/container_internal_linux.go +++ b/libpod/container_internal_linux.go @@ -571,7 +571,7 @@ func (c *Container) setupSystemd(mounts []spec.Mount, g generate.Generator) erro Destination: dest, Type: "tmpfs", Source: "tmpfs", - Options: append(options, "tmpcopyup", "size=65536k"), + Options: append(options, "tmpcopyup"), } g.AddMount(tmpfsMnt) } diff --git a/libpod/runtime_img.go b/libpod/runtime_img.go index a95cd1d7a..2bc9feb65 100644 --- a/libpod/runtime_img.go +++ b/libpod/runtime_img.go @@ -144,6 +144,10 @@ func storageContainers(imageID string, store storage.Store) ([]string, error) { // Removes the containers passed in the array. func removeStorageContainers(ctrIDs []string, store storage.Store) error { for _, ctrID := range ctrIDs { + if _, err := store.Unmount(ctrID, true); err != nil { + return errors.Wrapf(err, "could not unmount container %q to remove it", ctrID) + } + if err := store.DeleteContainer(ctrID); err != nil { return errors.Wrapf(err, "could not remove container %q", ctrID) } diff --git a/test/e2e/run_networking_test.go b/test/e2e/run_networking_test.go index 83befe730..a48f7c83e 100644 --- a/test/e2e/run_networking_test.go +++ b/test/e2e/run_networking_test.go @@ -531,8 +531,8 @@ var _ = Describe("Podman run networking", func() { SkipIfRemote() SkipIfRootless() netName := "podmantestnetwork" - ipAddr := "10.20.30.128" - create := podmanTest.Podman([]string{"network", "create", "--subnet", "10.20.30.0/24", netName}) + ipAddr := "10.25.30.128" + create := podmanTest.Podman([]string{"network", "create", "--subnet", "10.25.30.0/24", netName}) create.WaitWithDefaultTimeout() Expect(create.ExitCode()).To(BeZero()) @@ -540,5 +540,33 @@ var _ = Describe("Podman run networking", func() { run.WaitWithDefaultTimeout() Expect(run.ExitCode()).To(BeZero()) Expect(run.OutputToString()).To(ContainSubstring(ipAddr)) + + netrm := podmanTest.Podman([]string{"network", "rm", netName}) + netrm.WaitWithDefaultTimeout() + Expect(netrm.ExitCode()).To(BeZero()) + }) + + It("podman run with new:pod and static-ip", func() { + SkipIfRemote() + SkipIfRootless() + netName := "podmantestnetwork2" + ipAddr := "10.25.40.128" + podname := "testpod" + create := podmanTest.Podman([]string{"network", "create", "--subnet", "10.25.40.0/24", netName}) + create.WaitWithDefaultTimeout() + Expect(create.ExitCode()).To(BeZero()) + + run := podmanTest.Podman([]string{"run", "-t", "-i", "--rm", "--pod", "new:" + podname, "--net", netName, "--ip", ipAddr, ALPINE, "ip", "addr"}) + run.WaitWithDefaultTimeout() + Expect(run.ExitCode()).To(BeZero()) + Expect(run.OutputToString()).To(ContainSubstring(ipAddr)) + + podrm := podmanTest.Podman([]string{"pod", "rm", "-f", podname}) + podrm.WaitWithDefaultTimeout() + Expect(podrm.ExitCode()).To(BeZero()) + + netrm := podmanTest.Podman([]string{"network", "rm", netName}) + netrm.WaitWithDefaultTimeout() + Expect(netrm.ExitCode()).To(BeZero()) }) }) diff --git a/test/e2e/run_test.go b/test/e2e/run_test.go index 6c65a23e8..157b7d3d7 100644 --- a/test/e2e/run_test.go +++ b/test/e2e/run_test.go @@ -867,6 +867,14 @@ USER mail` Expect(match).To(BeTrue()) }) + It("podman run --pod new with hostname", func() { + hostname := "abc" + session := podmanTest.Podman([]string{"run", "--pod", "new:foobar", "--hostname", hostname, ALPINE, "cat", "/etc/hostname"}) + session.WaitWithDefaultTimeout() + Expect(session.ExitCode()).To(Equal(0)) + Expect(session.OutputToString()).To(ContainSubstring(hostname)) + }) + It("podman run --rm should work", func() { session := podmanTest.Podman([]string{"run", "--name", "test", "--rm", ALPINE, "ls"}) session.WaitWithDefaultTimeout() diff --git a/test/system/005-info.bats b/test/system/005-info.bats index c53ba8125..3f1efd364 100644 --- a/test/system/005-info.bats +++ b/test/system/005-info.bats @@ -3,8 +3,6 @@ load helpers @test "podman info - basic test" { - skip_if_remote "capitalization inconsistencies" - run_podman info expected_keys=" @@ -28,8 +26,6 @@ runRoot: } @test "podman info - json" { - skip_if_remote "capitalization inconsistencies" - run_podman info --format=json expr_nvr="[a-z0-9-]\\\+-[a-z0-9.]\\\+-[a-z0-9]\\\+\." diff --git a/test/system/010-images.bats b/test/system/010-images.bats index 2b1845d72..7fd731ca0 100644 --- a/test/system/010-images.bats +++ b/test/system/010-images.bats @@ -75,8 +75,6 @@ Size | [0-9]\\\+ } @test "podman images - filter" { - skip_if_remote "podman commit -q is broken in podman-remote" - run_podman inspect --format '{{.ID}}' $IMAGE iid=$output diff --git a/test/system/015-help.bats b/test/system/015-help.bats index 76d29d22c..4a3781012 100644 --- a/test/system/015-help.bats +++ b/test/system/015-help.bats @@ -178,6 +178,14 @@ function check_help() { # Called with no args -- start with 'podman --help'. check_help() will # recurse for any subcommands. check_help + + # Test for regression of #7273 (spurious "--remote" help on output) + for helpopt in help --help; do + run_podman $helpopt + is "${lines[0]}" "Manage pods, containers and images" \ + "podman $helpopt: first line of output" + done + } # vim: filetype=sh diff --git a/test/system/030-run.bats b/test/system/030-run.bats index 41863ba04..34afd5bae 100644 --- a/test/system/030-run.bats +++ b/test/system/030-run.bats @@ -63,7 +63,7 @@ echo $rand | 0 | $rand # 'run --preserve-fds' passes a number of additional file descriptors into the container @test "podman run --preserve-fds" { - skip_if_remote + skip_if_remote "preserve-fds is meaningless over remote" content=$(random_string 20) echo "$content" > $PODMAN_TMPDIR/tempfile @@ -150,8 +150,6 @@ echo $rand | 0 | $rand # 'run --rmi' deletes the image in the end unless it's used by another container @test "podman run --rmi" { - skip_if_remote - # Name of a nonlocal image. It should be pulled in by the first 'run' NONLOCAL_IMAGE=busybox run_podman 1 image exists $NONLOCAL_IMAGE diff --git a/test/system/060-mount.bats b/test/system/060-mount.bats index 7570f3ac4..d98a3eeb1 100644 --- a/test/system/060-mount.bats +++ b/test/system/060-mount.bats @@ -6,7 +6,7 @@ load helpers @test "podman mount - basic test" { # Only works with root (FIXME: does it work with rootless + vfs?) skip_if_rootless "mount does not work rootless" - skip_if_remote + skip_if_remote "mounting remote is meaningless" f_path=/tmp/tmpfile_$(random_string 8) f_content=$(random_string 30) diff --git a/test/system/075-exec.bats b/test/system/075-exec.bats index 38c6c2312..5f71e2acb 100644 --- a/test/system/075-exec.bats +++ b/test/system/075-exec.bats @@ -39,7 +39,7 @@ load helpers } @test "podman exec - leak check" { - skip_if_remote + skip_if_remote "test is meaningless over remote" # Start a container in the background then run exec command # three times and make sure no any exec pid hash file leak @@ -61,7 +61,7 @@ load helpers # Issue #4785 - piping to exec statement - fixed in #4818 # Issue #5046 - piping to exec truncates results (actually a conmon issue) @test "podman exec - cat from stdin" { - skip_if_remote + skip_if_remote "FIXME: pending #7360" run_podman run -d $IMAGE sh -c 'while [ ! -e /stop ]; do sleep 0.1;done' cid="$output" diff --git a/test/system/120-load.bats b/test/system/120-load.bats index 14dae4c8a..86b396c4a 100644 --- a/test/system/120-load.bats +++ b/test/system/120-load.bats @@ -27,13 +27,25 @@ verify_iid_and_name() { } @test "podman save to pipe and load" { + get_iid_and_name + # We can't use run_podman because that uses the BATS 'run' function # which redirects stdout and stderr. Here we need to guarantee # that podman's stdout is a pipe, not any other form of redirection - $PODMAN save --format oci-archive $IMAGE | cat >$PODMAN_TMPDIR/test.tar - [ $status -eq 0 ] + $PODMAN save --format oci-archive $IMAGE | cat >$archive + if [ "$status" -ne 0 ]; then + die "Command failed: podman save ... | cat" + fi + + # Make sure we can reload it + # FIXME: when/if 7337 gets fixed, add a random tag instead of rmi'ing + # FIXME: when/if 7371 gets fixed, use verify_iid_and_name() + run_podman rmi $iid + run_podman load -i $archive - run_podman load -i $PODMAN_TMPDIR/test.tar + # FIXME: cannot compare IID, see #7371 + run_podman images -a --format '{{.Repository}}:{{.Tag}}' + is "$output" "$IMAGE" "image preserves name across save/load" } diff --git a/test/system/200-pod.bats b/test/system/200-pod.bats index f3ec8a67c..7189d7e4b 100644 --- a/test/system/200-pod.bats +++ b/test/system/200-pod.bats @@ -96,9 +96,8 @@ function teardown() { run_podman rm $cid1 # ...then, from pause container, find the image ID of the pause image... - # FIXME: if #6283 gets implemented, use 'inspect --format ...' - run_podman pod inspect $podname - pause_cid=$(jq -r '.Containers[0].Id' <<<"$output") + run_podman pod inspect --format '{{(index .Containers 0).ID}}' $podname + pause_cid="$output" run_podman container inspect --format '{{.Image}}' $pause_cid pause_iid="$output" diff --git a/test/system/250-systemd.bats b/test/system/250-systemd.bats index b7035cdda..bbb5a10fb 100644 --- a/test/system/250-systemd.bats +++ b/test/system/250-systemd.bats @@ -18,7 +18,7 @@ fi UNIT_FILE="$UNIT_DIR/$SERVICE_NAME.service" function setup() { - skip_if_remote + skip_if_remote "systemd tests are meaningless over remote" basic_setup } diff --git a/test/system/260-sdnotify.bats b/test/system/260-sdnotify.bats index 7be4be983..62d3c1497 100644 --- a/test/system/260-sdnotify.bats +++ b/test/system/260-sdnotify.bats @@ -10,7 +10,7 @@ _SOCAT_PID= _SOCAT_LOG= function setup() { - skip_if_remote + skip_if_remote "systemd tests are meaningless over remote" skip "FIXME FIXME FIXME, is this what's causing the CI hang???" diff --git a/test/system/500-networking.bats b/test/system/500-networking.bats index 234bc1187..0fae3dcd3 100644 --- a/test/system/500-networking.bats +++ b/test/system/500-networking.bats @@ -7,7 +7,7 @@ load helpers # Copied from tsweeney's https://github.com/containers/podman/issues/4827 @test "podman networking: port on localhost" { - skip_if_remote + skip_if_remote "FIXME: reevaluate this one after #7360 is fixed" random_1=$(random_string 30) random_2=$(random_string 30) @@ -62,8 +62,6 @@ load helpers # Issue #5466 - port-forwarding doesn't work with this option and -d @test "podman networking: port with --userns=keep-id" { - skip_if_remote - # FIXME: randomize port, and create second random host port myport=54321 diff --git a/vendor/github.com/containers/image/v5/docker/docker_client.go b/vendor/github.com/containers/image/v5/docker/docker_client.go index 9461bc91a..e4308def1 100644 --- a/vendor/github.com/containers/image/v5/docker/docker_client.go +++ b/vendor/github.com/containers/image/v5/docker/docker_client.go @@ -331,7 +331,6 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima // Results holds the results returned by the /v1/search endpoint Results []SearchResult `json:"results"` } - v2Res := &V2Results{} v1Res := &V1Results{} // Get credentials from authfile for the underlying hostname @@ -388,31 +387,55 @@ func SearchRegistry(ctx context.Context, sys *types.SystemContext, registry, ima } logrus.Debugf("trying to talk to v2 search endpoint") - resp, err := client.makeRequest(ctx, "GET", "/v2/_catalog", nil, nil, v2Auth, nil) - if err != nil { - logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err) - } else { + searchRes := []SearchResult{} + path := "/v2/_catalog" + for len(searchRes) < limit { + resp, err := client.makeRequest(ctx, "GET", path, nil, nil, v2Auth, nil) + if err != nil { + logrus.Debugf("error getting search results from v2 endpoint %q: %v", registry, err) + return nil, errors.Wrapf(err, "couldn't search registry %q", registry) + } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { logrus.Errorf("error getting search results from v2 endpoint %q: %v", registry, httpResponseToError(resp, "")) - } else { - if err := json.NewDecoder(resp.Body).Decode(v2Res); err != nil { - return nil, err + return nil, errors.Wrapf(err, "couldn't search registry %q", registry) + } + v2Res := &V2Results{} + if err := json.NewDecoder(resp.Body).Decode(v2Res); err != nil { + return nil, err + } + + for _, repo := range v2Res.Repositories { + if len(searchRes) == limit { + break } - searchRes := []SearchResult{} - for _, repo := range v2Res.Repositories { - if strings.Contains(repo, image) { - res := SearchResult{ - Name: repo, - } - searchRes = append(searchRes, res) + if strings.Contains(repo, image) { + res := SearchResult{ + Name: repo, } + searchRes = append(searchRes, res) } - return searchRes, nil } - } - return nil, errors.Wrapf(err, "couldn't search registry %q", registry) + link := resp.Header.Get("Link") + if link == "" { + break + } + linkURLStr := strings.Trim(strings.Split(link, ";")[0], "<>") + linkURL, err := url.Parse(linkURLStr) + if err != nil { + return searchRes, err + } + + // can be relative or absolute, but we only want the path (and I + // guess we're in trouble if it forwards to a new place...) + path = linkURL.Path + if linkURL.RawQuery != "" { + path += "?" + path += linkURL.RawQuery + } + } + return searchRes, nil } // makeRequest creates and executes a http.Request with the specified parameters, adding authentication and TLS options for the Docker client. diff --git a/vendor/github.com/containers/image/v5/version/version.go b/vendor/github.com/containers/image/v5/version/version.go index 114bce387..2f56effae 100644 --- a/vendor/github.com/containers/image/v5/version/version.go +++ b/vendor/github.com/containers/image/v5/version/version.go @@ -8,7 +8,7 @@ const ( // VersionMinor is for functionality in a backwards-compatible manner VersionMinor = 5 // VersionPatch is for backwards-compatible bug fixes - VersionPatch = 1 + VersionPatch = 2 // VersionDev indicates development branch. Releases will be empty string. VersionDev = "" diff --git a/vendor/modules.txt b/vendor/modules.txt index 0ab37e30c..c6e098f58 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -95,7 +95,7 @@ github.com/containers/common/pkg/sysinfo github.com/containers/common/version # github.com/containers/conmon v2.0.19+incompatible github.com/containers/conmon/runner/config -# github.com/containers/image/v5 v5.5.1 +# github.com/containers/image/v5 v5.5.2 github.com/containers/image/v5/copy github.com/containers/image/v5/directory github.com/containers/image/v5/directory/explicitfilepath |