Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Show c/storage (Buildah/CRI-O) containers in ps #7290

Merged
merged 1 commit into from
Sep 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion cmd/podman/containers/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
tm "github.com/buger/goterm"
"github.com/containers/buildah/pkg/formats"
"github.com/containers/podman/v2/cmd/podman/registry"
"github.com/containers/podman/v2/cmd/podman/utils"
"github.com/containers/podman/v2/cmd/podman/validate"
"github.com/containers/podman/v2/pkg/domain/entities"
"github.com/cri-o/ocicni/pkg/ocicni"
Expand Down Expand Up @@ -56,9 +57,9 @@ func init() {
func listFlagSet(flags *pflag.FlagSet) {
flags.BoolVarP(&listOpts.All, "all", "a", false, "Show all the containers, default is only running containers")
flags.StringSliceVarP(&filters, "filter", "f", []string{}, "Filter output based on conditions given")
flags.BoolVar(&listOpts.Storage, "storage", false, "Show containers in storage not controlled by Podman")
flags.StringVar(&listOpts.Format, "format", "", "Pretty-print containers to JSON or using a Go template")
flags.IntVarP(&listOpts.Last, "last", "n", -1, "Print the n last created containers (all states)")
flags.BoolVar(&listOpts.Namespace, "namespace", false, "Display namespace information")
flags.BoolVar(&listOpts.Namespace, "ns", false, "Display namespace information")
flags.BoolVar(&noTrunc, "no-trunc", false, "Display the extended information")
flags.BoolVarP(&listOpts.Pod, "pod", "p", false, "Print the ID and name of the pod the containers are associated with")
Expand All @@ -69,6 +70,7 @@ func listFlagSet(flags *pflag.FlagSet) {

sort := validate.Value(&listOpts.Sort, "command", "created", "id", "image", "names", "runningfor", "size", "status")
flags.Var(sort, "sort", "Sort output by: "+sort.Choices())
flags.SetNormalizeFunc(utils.AliasFlags)
}
func checkFlags(c *cobra.Command) error {
// latest, and last are mutually exclusive.
Expand Down Expand Up @@ -102,6 +104,14 @@ func checkFlags(c *cobra.Command) error {
if listOpts.Watch > 0 && listOpts.Latest {
return errors.New("the watch and latest flags cannot be used together")
}
cfg := registry.PodmanConfig()
if cfg.Engine.Namespace != "" {
if c.Flag("storage").Changed && listOpts.Storage {
return errors.New("--namespace and --storage flags can not both be set")
}
listOpts.Storage = false
}

return nil
}

Expand Down
2 changes: 2 additions & 0 deletions cmd/podman/utils/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
name = "network"
case "timeout":
name = "time"
case "namespace":
name = "ns"
}
return pflag.NormalizedName(name)
}
1 change: 1 addition & 0 deletions completions/bash/podman
Original file line number Diff line number Diff line change
Expand Up @@ -2679,6 +2679,7 @@ _podman_ps() {
--pod -p
--quiet -q
--size -s
--storage
--namespace --ns
--sync
"
Expand Down
4 changes: 3 additions & 1 deletion docs/source/markdown/podman-build.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ When the URL is an Containerfile, the Containerfile is downloaded to a temporary

When a Git repository is set as the URL, the repository is cloned locally and then set as the context.

NOTE: `podman build` uses code sourced from the `buildah` project to build container images. This `buildah` code creates `buildah` containers for the `RUN` options in container storage. In certain situations, when the `podman build` crashes or users kill the `podman build` process, these external containers can be left in container storage. Use the `podman ps --all --storage` command to see these contaienrs. External containers can be removed with the `podman rm --storage` command.

## OPTIONS

**--add-host**=*host*
Expand Down Expand Up @@ -804,7 +806,7 @@ If you are using a useradd command within a Containerfile with a large UID/GID,
If you are using `useradd` within your build script, you should pass the `--no-log-init or -l` option to the `useradd` command. This option tells useradd to stop creating the lastlog file.

## SEE ALSO
podman(1), buildah(1), containers-registries.conf(5), crun(8), runc(8), useradd(8)
podman(1), buildah(1), containers-registries.conf(5), crun(8), runc(8), useradd(8), podman-ps(1), podman-rm(1)

## HISTORY
Aug 2020, Additional options and .dockerignore added by Dan Walsh <[email protected]>
Expand Down
19 changes: 17 additions & 2 deletions docs/source/markdown/podman-ps.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,18 @@ all the containers information. By default it lists:

**--all**, **-a**

Show all the containers, default is only running containers
Show all the containers created by Podman, default is only running containers.

Note: Podman shares containers storage with other tools such as Buildah and CRI-O. In some cases these `external` containers might also exist in the same storage. Use the `--storage` option to see these external containers. External containers show the 'storage' status.

**--pod**, **-p**

Display the pods the containers are associated with

**--storage**

Display external containers that are not controlled by Podman but are stored in containers storage. These external containers are generally created via other container technology such as Buildah or CRI-O and may depend on the same container images that Podman is also using. External containers are denoted with either a 'buildah' or 'storage' in the COMMAND and STATUS column of the ps output. Only used with the --all option.

**--no-trunc**

Display the extended information
Expand Down Expand Up @@ -174,11 +180,20 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS

```

```
$ podman ps --storage -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
69ed779d8ef9f redis:alpine "redis-server" 25 hours ago Created 6379/tcp k8s_container1_podsandbox1_redhat.test.crio_redhat-test-crio_1
38a8a78596f9 docker.io/library/busybox:latest buildah 2 hours ago storage busybox-working-container
fd7b786b5c32 docker.io/library/alpine:latest buildah 2 hours ago storage alpine-working-container
f78620804e00 scratch buildah 2 hours ago storage working-container
```

## ps
Print a list of containers

## SEE ALSO
podman(1)
podman(1), buildah(1), crio(8)

## HISTORY
August 2017, Originally compiled by Urvashi Mohnani <[email protected]>
8 changes: 4 additions & 4 deletions docs/source/markdown/podman-rm.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ The latest option is not supported on the remote client.

**--storage**

Remove the container from the storage library only.
This is only possible with containers that are not present in libpod (cannot be seen by **podman ps**).
It is used to remove containers from **podman build** and **buildah**, and orphan containers which were only partially removed by **podman rm**.
Remove external containers from the storage library.
This is only possible with containers that are not present in libpod can be seen by **podman ps --all --storage**).
It is used to remove external containers from **podman build** and **buildah**, and orphan containers which were only partially removed by **podman rm**.
The storage option conflicts with the **--all**, **--latest**, and **--volumes** options.

**--volumes**, **-v**
Expand Down Expand Up @@ -96,7 +96,7 @@ $ podman rm -f --latest
**125** The command fails for a reason other than container did not exist or is paused/running

## SEE ALSO
podman(1), podman-image-rm(1)
podman(1), podman-image-rm(1), podman-ps(1), podman-build(1)

## HISTORY
August 2017, Originally compiled by Ryan Cole <[email protected]>
4 changes: 4 additions & 0 deletions libpod/define/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,4 +161,8 @@ var (
// ErrNetworkOnPodContainer indicates the user wishes to alter network attributes on a container
// in a pod. This cannot be done as the infra container has all the network information
ErrNetworkOnPodContainer = errors.New("network cannot be configured when it is shared with a pod")

// ErrStoreNotInitialized indicates that the container storage was never
// initilized.
ErrStoreNotInitialized = errors.New("the container storage was never initilized")
)
8 changes: 8 additions & 0 deletions libpod/image/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,6 +466,14 @@ func (ir *Runtime) getImage(image string) (*storage.Image, error) {
return img, nil
}

func (ir *Runtime) ImageNames(id string) ([]string, error) {
myImage, err := ir.getImage(id)
if err != nil {
return nil, errors.Wrapf(err, "error getting image %s ", id)
}
return myImage.Names, nil
}

// GetImages retrieves all images present in storage
func (ir *Runtime) GetImages() ([]*Image, error) {
return ir.getImages(false)
Expand Down
2 changes: 1 addition & 1 deletion libpod/image/prune.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ func (ir *Runtime) PruneImages(ctx context.Context, all bool, filter []string) (
}
if err := p.Remove(ctx, true); err != nil {
if errors.Cause(err) == storage.ErrImageUsedByContainer {
logrus.Warnf("Failed to prune image %s as it is in use: %v", p.ID(), err)
logrus.Warnf("Failed to prune image %s as it is in use: %v.\nA container associated with containers/storage i.e. Buildah, CRI-O, etc., maybe associated with this image.\nUsing the rmi command with the --force option will remove the container and image, but may cause failures for other dependent systems.", p.ID(), err)
continue
}
return nil, errors.Wrap(err, "failed to prune image")
Expand Down
33 changes: 33 additions & 0 deletions libpod/runtime_ctr.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ import (
"strings"
"time"

"github.com/containers/buildah"
"github.com/containers/common/pkg/config"
"github.com/containers/podman/v2/libpod/define"
"github.com/containers/podman/v2/libpod/events"
"github.com/containers/podman/v2/pkg/cgroups"
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/storage"
"github.com/containers/storage/pkg/stringid"
"github.com/docker/go-units"
spec "github.com/opencontainers/runtime-spec/specs-go"
Expand Down Expand Up @@ -905,3 +907,34 @@ func (r *Runtime) PruneContainers(filterFuncs []ContainerFilter) (map[string]int
}
return prunedContainers, pruneErrors, nil
}

// StorageContainers returns a list of containers from containers/storage that
// are not currently known to Podman.
func (r *Runtime) StorageContainers() ([]storage.Container, error) {

if r.store == nil {
return nil, define.ErrStoreNotInitialized
}

storeContainers, err := r.store.Containers()
if err != nil {
return nil, errors.Wrapf(err, "error reading list of all storage containers")
}
retCtrs := []storage.Container{}
for _, container := range storeContainers {
exists, err := r.state.HasContainer(container.ID)
if err != nil && err != define.ErrNoSuchCtr {
return nil, errors.Wrapf(err, "failed to check if %s container exists in database", container.ID)
}
if exists {
continue
}
retCtrs = append(retCtrs, container)
}

return retCtrs, nil
}

func (r *Runtime) IsBuildahContainer(id string) (bool, error) {
return buildah.IsContainer(id, r.store)
}
1 change: 1 addition & 0 deletions pkg/domain/entities/containers.go
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ type ContainerListOptions struct {
Quiet bool
Size bool
Sort string
Storage bool
Sync bool
Watch uint
}
Expand Down
85 changes: 82 additions & 3 deletions pkg/ps/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
lpfilters "github.com/containers/podman/v2/libpod/filters"
"github.com/containers/podman/v2/pkg/domain/entities"
psdefine "github.com/containers/podman/v2/pkg/ps/define"
"github.com/containers/storage"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
)
Expand Down Expand Up @@ -54,12 +55,12 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
return nil, err
}
if options.Last > 0 {
// Sort the containers we got
// Sort the libpod containers
sort.Sort(SortCreateTime{SortContainers: cons})
// we should perform the lopping before we start getting
// the expensive information on containers
if options.Last < len(cons) {
cons = cons[len(cons)-options.Last:]
cons = cons[:options.Last]
}
}
for _, con := range cons {
Expand All @@ -68,7 +69,31 @@ func GetContainerLists(runtime *libpod.Runtime, options entities.ContainerListOp
return nil, err
}
pss = append(pss, listCon)
}

if options.All && options.Storage {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be ||, not &&'

externCons, err := runtime.StorageContainers()
if err != nil {
return nil, err
}

for _, con := range externCons {
listCon, err := ListStorageContainer(runtime, con, options)
if err != nil {
return nil, err
}
pss = append(pss, listCon)
}
}

// Sort the containers we got
sort.Sort(SortPSCreateTime{SortPSContainers: pss})

if options.Last > 0 {
// only return the "last" containers caller requested
if options.Last < len(pss) {
pss = pss[:options.Last]
}
}
return pss, nil
}
Expand Down Expand Up @@ -199,6 +224,48 @@ func ListContainerBatch(rt *libpod.Runtime, ctr *libpod.Container, opts entities
return ps, nil
}

func ListStorageContainer(rt *libpod.Runtime, ctr storage.Container, opts entities.ContainerListOptions) (entities.ListContainer, error) {
name := "unknown"
if len(ctr.Names) > 0 {
name = ctr.Names[0]
}

ps := entities.ListContainer{
ID: ctr.ID,
Created: ctr.Created.Unix(),
ImageID: ctr.ImageID,
State: "storage",
Names: []string{name},
}

buildahCtr, err := rt.IsBuildahContainer(ctr.ID)
if err != nil {
return ps, errors.Wrapf(err, "error determining buildah container for container %s", ctr.ID)
}

if buildahCtr {
ps.Command = []string{"buildah"}
} else {
ps.Command = []string{"storage"}
}

imageName := ""
if ctr.ImageID != "" {
names, err := rt.ImageRuntime().ImageNames(ctr.ImageID)
if err != nil {
return ps, err
}
if len(names) > 0 {
imageName = names[0]
}
} else if buildahCtr {
imageName = "scratch"
}

ps.Image = imageName
return ps, nil
}

func getNamespaceInfo(path string) (string, error) {
val, err := os.Readlink(path)
if err != nil {
Expand All @@ -223,5 +290,17 @@ func (a SortContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
type SortCreateTime struct{ SortContainers }

func (a SortCreateTime) Less(i, j int) bool {
return a.SortContainers[i].CreatedTime().Before(a.SortContainers[j].CreatedTime())
return a.SortContainers[i].CreatedTime().After(a.SortContainers[j].CreatedTime())
}

// SortPSContainers helps us set-up ability to sort by createTime
type SortPSContainers []entities.ListContainer

func (a SortPSContainers) Len() int { return len(a) }
func (a SortPSContainers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }

type SortPSCreateTime struct{ SortPSContainers }

func (a SortPSCreateTime) Less(i, j int) bool {
return a.SortPSContainers[i].Created > a.SortPSContainers[j].Created
}