mirror of
https://github.com/containers/podman.git
synced 2025-07-03 09:17:15 +08:00
Add support for external container
External containers are containers created outside of Podman. For example Buildah and CRI-O Containers. $ buildah from alpine alpine-working-container $ buildah run alpine-working-container touch /test $ podman container exists --external alpine-working-container $ podman container diff alpine-working-container C /etc A /test Added --external flag to refer to external containers, rather then --storage. Added --external for podman container exists and modified podman ps to use --external rather then --storage. It was felt that --storage would confuse the user into thinking about changing the storage driver or options. --storage is still supported through the use of aliases. Finally podman contianer diff, does not require the --external flag, since it there is little change of users making the mistake, and would just be a pain for the user to remember the flag. podman container exists --external is required because it could fool scripts that rely on the existance of a Podman container, and there is a potential for a partial deletion of a container, which could mess up existing users. Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -12,10 +12,10 @@ var (
|
||||
containerExistsDescription = `If the named container exists in local storage, podman container exists exits with 0, otherwise the exit code will be 1.`
|
||||
|
||||
existsCommand = &cobra.Command{
|
||||
Use: "exists CONTAINER",
|
||||
Use: "exists [flags] CONTAINER",
|
||||
Short: "Check if a container exists in local storage",
|
||||
Long: containerExistsDescription,
|
||||
Example: `podman container exists containerID
|
||||
Example: `podman container exists --external containerID
|
||||
podman container exists myctr || podman run --name myctr [etc...]`,
|
||||
RunE: exists,
|
||||
Args: cobra.ExactArgs(1),
|
||||
@ -29,10 +29,19 @@ func init() {
|
||||
Command: existsCommand,
|
||||
Parent: containerCmd,
|
||||
})
|
||||
flags := existsCommand.Flags()
|
||||
flags.Bool("external", false, "Check external storage containers as well as Podman containers")
|
||||
}
|
||||
|
||||
func exists(cmd *cobra.Command, args []string) error {
|
||||
response, err := registry.ContainerEngine().ContainerExists(context.Background(), args[0])
|
||||
external, err := cmd.Flags().GetBool("external")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
options := entities.ContainerExistsOptions{
|
||||
External: external,
|
||||
}
|
||||
response, err := registry.ContainerEngine().ContainerExists(context.Background(), args[0], options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ 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.BoolVar(&listOpts.Storage, "external", 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, "ns", false, "Display namespace information")
|
||||
|
@ -48,7 +48,10 @@ func diff(cmd *cobra.Command, args []string) error {
|
||||
return containers.Diff(cmd, args, diffOpts)
|
||||
}
|
||||
|
||||
if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0]); err != nil {
|
||||
options := entities.ContainerExistsOptions{
|
||||
External: true,
|
||||
}
|
||||
if found, err := registry.ContainerEngine().ContainerExists(registry.GetContext(), args[0], options); err != nil {
|
||||
return err
|
||||
} else if found.Value {
|
||||
return containers.Diff(cmd, args, diffOpts)
|
||||
|
@ -21,6 +21,8 @@ func AliasFlags(f *pflag.FlagSet, name string) pflag.NormalizedName {
|
||||
name = "time"
|
||||
case "namespace":
|
||||
name = "ns"
|
||||
case "storage":
|
||||
name = "external"
|
||||
}
|
||||
return pflag.NormalizedName(name)
|
||||
}
|
||||
|
@ -2468,7 +2468,6 @@ _podman_rm() {
|
||||
-i
|
||||
--latest
|
||||
-l
|
||||
--storage
|
||||
--volumes
|
||||
-v
|
||||
"
|
||||
@ -2696,7 +2695,7 @@ _podman_ps() {
|
||||
--pod -p
|
||||
--quiet -q
|
||||
--size -s
|
||||
--storage
|
||||
--external
|
||||
--namespace --ns
|
||||
--sync
|
||||
"
|
||||
@ -3168,7 +3167,11 @@ _podman_container_exists() {
|
||||
"
|
||||
|
||||
local boolean_options="
|
||||
"
|
||||
--external
|
||||
-h
|
||||
--help
|
||||
"
|
||||
|
||||
case "$cur" in
|
||||
-*)
|
||||
COMPREPLY=($(compgen -W "$boolean_options $options_with_args" -- "$cur"))
|
||||
|
@ -4,7 +4,7 @@
|
||||
podman-container-exists - Check if a container exists in local storage
|
||||
|
||||
## SYNOPSIS
|
||||
**podman container exists** *container*
|
||||
**podman container exists** [*options*] *container*
|
||||
|
||||
## DESCRIPTION
|
||||
**podman container exists** checks if a container exists in local storage. The **ID** or **Name**
|
||||
@ -14,6 +14,9 @@ was an issue accessing the local storage.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
**--external**=*true|false*
|
||||
Check for external containers as well as Podman containers. These external containers are generally created via other container technology such as Buildah or CRI-O.
|
||||
|
||||
**-h**, **--help**
|
||||
Print usage statement
|
||||
|
||||
@ -33,6 +36,13 @@ $ echo $?
|
||||
1
|
||||
```
|
||||
|
||||
Check if an container called `ubi8-working-container` created via Buildah exists in local storage (the container does not actually exist).
|
||||
```
|
||||
$ podman container exists --external ubi8-working-container
|
||||
$ echo $?
|
||||
1
|
||||
```
|
||||
|
||||
## SEE ALSO
|
||||
podman(1)
|
||||
|
||||
|
@ -34,70 +34,12 @@ all the containers information. By default it lists:
|
||||
|
||||
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.
|
||||
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 `--external` option to see these external containers. External containers show the 'storage' status.
|
||||
|
||||
**--pod**, **-p**
|
||||
|
||||
Display the pods the containers are associated with
|
||||
|
||||
**--storage**
|
||||
**--external**
|
||||
|
||||
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
|
||||
|
||||
**--quiet**, **-q**
|
||||
|
||||
Print the numeric IDs of the containers only
|
||||
|
||||
**--format**=*format*
|
||||
|
||||
Pretty-print containers to JSON or using a Go template
|
||||
|
||||
Valid placeholders for the Go template are listed below:
|
||||
|
||||
| **Placeholder** | **Description** |
|
||||
| --------------- | ------------------------------------------------ |
|
||||
| .ID | Container ID |
|
||||
| .Image | Image Name/ID |
|
||||
| .ImageID | Image ID |
|
||||
| .Command | Quoted command used |
|
||||
| .CreatedAt | Creation time for container |
|
||||
| .RunningFor | Time elapsed since container was started |
|
||||
| .Status | Status of container |
|
||||
| .Pod | Pod the container is associated with |
|
||||
| .Ports | Exposed ports |
|
||||
| .Size | Size of container |
|
||||
| .Names | Name of container |
|
||||
| .Labels | All the labels assigned to the container |
|
||||
| .Mounts | Volumes mounted in the container |
|
||||
|
||||
**--sort**
|
||||
|
||||
Sort by command, created, id, image, names, runningfor, size, or status",
|
||||
Note: Choosing size will sort by size of rootFs, not alphabetically like the rest of the options
|
||||
Default: created
|
||||
|
||||
**--size**, **-s**
|
||||
|
||||
Display the total file size
|
||||
|
||||
**--last**, **-n**
|
||||
|
||||
Print the n last created containers (all states)
|
||||
|
||||
**--latest**, **-l**
|
||||
|
||||
Show the latest container created (all states)
|
||||
|
||||
The latest option is not supported on the remote client.
|
||||
|
||||
**--namespace**, **--ns**
|
||||
|
||||
Display namespace information
|
||||
|
||||
**--filter**, **-f**
|
||||
|
||||
Filter what containers are shown in the output.
|
||||
@ -120,10 +62,68 @@ Valid filters are listed below:
|
||||
| volume | [VolumeName] or [MountpointDestination] Volume mounted in container |
|
||||
| health | [Status] healthy or unhealthy |
|
||||
|
||||
**--format**=*format*
|
||||
|
||||
Pretty-print containers to JSON or using a Go template
|
||||
|
||||
Valid placeholders for the Go template are listed below:
|
||||
|
||||
| **Placeholder** | **Description** |
|
||||
| --------------- | ------------------------------------------------ |
|
||||
| .ID | Container ID |
|
||||
| .Image | Image Name/ID |
|
||||
| .ImageID | Image ID |
|
||||
| .Command | Quoted command used |
|
||||
| .CreatedAt | Creation time for container |
|
||||
| .RunningFor | Time elapsed since container was started |
|
||||
| .Status | Status of container |
|
||||
| .Pod | Pod the container is associated with |
|
||||
| .Ports | Exposed ports |
|
||||
| .Size | Size of container |
|
||||
| .Names | Name of container |
|
||||
| .Labels | All the labels assigned to the container |
|
||||
| .Mounts | Volumes mounted in the container |
|
||||
|
||||
**--help**, **-h**
|
||||
|
||||
Print usage statement
|
||||
|
||||
**--last**, **-n**
|
||||
|
||||
Print the n last created containers (all states)
|
||||
|
||||
**--latest**, **-l**
|
||||
|
||||
Show the latest container created (all states)
|
||||
|
||||
The latest option is not supported on the remote client.
|
||||
|
||||
**--namespace**, **--ns**
|
||||
|
||||
Display namespace information
|
||||
|
||||
**--no-trunc**
|
||||
|
||||
Display the extended information
|
||||
|
||||
**--pod**, **-p**
|
||||
|
||||
Display the pods the containers are associated with
|
||||
|
||||
**--quiet**, **-q**
|
||||
|
||||
Print the numeric IDs of the containers only
|
||||
|
||||
**--sort**
|
||||
|
||||
Sort by command, created, id, image, names, runningfor, size, or status",
|
||||
Note: Choosing size will sort by size of rootFs, not alphabetically like the rest of the options
|
||||
Default: created
|
||||
|
||||
**--size**, **-s**
|
||||
|
||||
Display the total file size
|
||||
|
||||
**--sync**
|
||||
|
||||
Force a sync of container state with the OCI runtime.
|
||||
@ -181,7 +181,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS
|
||||
```
|
||||
|
||||
```
|
||||
$ podman ps --storage -a
|
||||
$ podman ps --external -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
|
||||
|
@ -19,13 +19,30 @@ import (
|
||||
)
|
||||
|
||||
func ContainerExists(w http.ResponseWriter, r *http.Request) {
|
||||
decoder := r.Context().Value("decoder").(*schema.Decoder)
|
||||
runtime := r.Context().Value("runtime").(*libpod.Runtime)
|
||||
// Now use the ABI implementation to prevent us from having duplicate
|
||||
// code.
|
||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||
|
||||
name := utils.GetName(r)
|
||||
report, err := containerEngine.ContainerExists(r.Context(), name)
|
||||
query := struct {
|
||||
External bool `schema:"external"`
|
||||
}{
|
||||
// override any golang type defaults
|
||||
}
|
||||
|
||||
if err := decoder.Decode(&query, r.URL.Query()); err != nil {
|
||||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||
errors.Wrapf(err, "failed to parse parameters for %s", r.URL.String()))
|
||||
return
|
||||
}
|
||||
|
||||
options := entities.ContainerExistsOptions{
|
||||
External: query.External,
|
||||
}
|
||||
|
||||
report, err := containerEngine.ContainerExists(r.Context(), name, options)
|
||||
if err != nil {
|
||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||
utils.ContainerNotFound(w, name, err)
|
||||
|
@ -322,12 +322,14 @@ func Wait(ctx context.Context, nameOrID string, condition *define.ContainerStatu
|
||||
// Exists is a quick, light-weight way to determine if a given container
|
||||
// exists in local storage. The nameOrID can be a container name
|
||||
// or a partial/full ID.
|
||||
func Exists(ctx context.Context, nameOrID string) (bool, error) {
|
||||
func Exists(ctx context.Context, nameOrID string, external bool) (bool, error) {
|
||||
conn, err := bindings.GetClient(ctx)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", nil, nil, nameOrID)
|
||||
params := url.Values{}
|
||||
params.Set("external", strconv.FormatBool(external))
|
||||
response, err := conn.DoRequest(nil, http.MethodGet, "/containers/%s/exists", params, nil, nameOrID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
@ -405,7 +405,7 @@ var _ = Describe("Podman containers ", func() {
|
||||
|
||||
It("podman bogus container does not exist in local storage", func() {
|
||||
// Bogus container existence check should fail
|
||||
containerExists, err := containers.Exists(bt.conn, "foobar")
|
||||
containerExists, err := containers.Exists(bt.conn, "foobar", false)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(containerExists).To(BeFalse())
|
||||
})
|
||||
@ -415,7 +415,7 @@ var _ = Describe("Podman containers ", func() {
|
||||
var name = "top"
|
||||
_, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
Expect(err).To(BeNil())
|
||||
containerExists, err := containers.Exists(bt.conn, name)
|
||||
containerExists, err := containers.Exists(bt.conn, name, false)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(containerExists).To(BeTrue())
|
||||
})
|
||||
@ -425,7 +425,7 @@ var _ = Describe("Podman containers ", func() {
|
||||
var name = "top"
|
||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
Expect(err).To(BeNil())
|
||||
containerExists, err := containers.Exists(bt.conn, cid)
|
||||
containerExists, err := containers.Exists(bt.conn, cid, false)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(containerExists).To(BeTrue())
|
||||
})
|
||||
@ -435,7 +435,7 @@ var _ = Describe("Podman containers ", func() {
|
||||
var name = "top"
|
||||
cid, err := bt.RunTopContainer(&name, bindings.PFalse, nil)
|
||||
Expect(err).To(BeNil())
|
||||
containerExists, err := containers.Exists(bt.conn, cid[0:12])
|
||||
containerExists, err := containers.Exists(bt.conn, cid[0:12], false)
|
||||
Expect(err).To(BeNil())
|
||||
Expect(containerExists).To(BeTrue())
|
||||
})
|
||||
@ -455,7 +455,7 @@ var _ = Describe("Podman containers ", func() {
|
||||
Expect(err).To(BeNil())
|
||||
err = containers.Kill(bt.conn, name, "SIGINT")
|
||||
Expect(err).To(BeNil())
|
||||
_, err = containers.Exists(bt.conn, name)
|
||||
_, err = containers.Exists(bt.conn, name, false)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
@ -466,7 +466,7 @@ var _ = Describe("Podman containers ", func() {
|
||||
Expect(err).To(BeNil())
|
||||
err = containers.Kill(bt.conn, cid, "SIGTERM")
|
||||
Expect(err).To(BeNil())
|
||||
_, err = containers.Exists(bt.conn, cid)
|
||||
_, err = containers.Exists(bt.conn, cid, false)
|
||||
Expect(err).To(BeNil())
|
||||
})
|
||||
|
||||
|
@ -246,6 +246,11 @@ type ExecOptions struct {
|
||||
WorkDir string
|
||||
}
|
||||
|
||||
// ContainerExistsOptions describes the cli values to check if a container exists
|
||||
type ContainerExistsOptions struct {
|
||||
External bool
|
||||
}
|
||||
|
||||
// ContainerStartOptions describes the val from the
|
||||
// CLI needed to start a container
|
||||
type ContainerStartOptions struct {
|
||||
|
@ -21,7 +21,7 @@ type ContainerEngine interface {
|
||||
ContainerDiff(ctx context.Context, nameOrID string, options DiffOptions) (*DiffReport, error)
|
||||
ContainerExec(ctx context.Context, nameOrID string, options ExecOptions, streams define.AttachStreams) (int, error)
|
||||
ContainerExecDetached(ctx context.Context, nameOrID string, options ExecOptions) (string, error)
|
||||
ContainerExists(ctx context.Context, nameOrID string) (*BoolReport, error)
|
||||
ContainerExists(ctx context.Context, nameOrID string, options ContainerExistsOptions) (*BoolReport, error)
|
||||
ContainerExport(ctx context.Context, nameOrID string, options ContainerExportOptions) error
|
||||
ContainerInit(ctx context.Context, namesOrIds []string, options ContainerInitOptions) ([]*ContainerInitReport, error)
|
||||
ContainerInspect(ctx context.Context, namesOrIds []string, options InspectOptions) ([]*ContainerInspectReport, []error, error)
|
||||
|
@ -75,15 +75,17 @@ func getContainersByContext(all, latest bool, names []string, runtime *libpod.Ru
|
||||
}
|
||||
|
||||
// ContainerExists returns whether the container exists in container storage
|
||||
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
|
||||
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
|
||||
_, err := ic.Libpod.LookupContainer(nameOrID)
|
||||
if err != nil {
|
||||
if errors.Cause(err) != define.ErrNoSuchCtr {
|
||||
return nil, err
|
||||
}
|
||||
// Check if container exists in storage
|
||||
if _, storageErr := ic.Libpod.StorageContainer(nameOrID); storageErr == nil {
|
||||
err = nil
|
||||
if options.External {
|
||||
// Check if container exists in storage
|
||||
if _, storageErr := ic.Libpod.StorageContainer(nameOrID); storageErr == nil {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return &entities.BoolReport{Value: err == nil}, nil
|
||||
|
@ -29,8 +29,8 @@ func (ic *ContainerEngine) ContainerRunlabel(ctx context.Context, label string,
|
||||
return errors.New("not implemented")
|
||||
}
|
||||
|
||||
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string) (*entities.BoolReport, error) {
|
||||
exists, err := containers.Exists(ic.ClientCxt, nameOrID)
|
||||
func (ic *ContainerEngine) ContainerExists(ctx context.Context, nameOrID string, options entities.ContainerExistsOptions) (*entities.BoolReport, error) {
|
||||
exists, err := containers.Exists(ic.ClientCxt, nameOrID, options.External)
|
||||
return &entities.BoolReport{Value: exists}, err
|
||||
}
|
||||
|
||||
|
@ -471,8 +471,11 @@ json-file | f
|
||||
run buildah from $IMAGE
|
||||
cid="$output"
|
||||
|
||||
# exists should fail
|
||||
run_podman 1 container exists $cid
|
||||
|
||||
# exists should succeed
|
||||
run_podman container exists $cid
|
||||
run_podman container exists --external $cid
|
||||
|
||||
run buildah rm $cid
|
||||
}
|
||||
|
Reference in New Issue
Block a user