mirror of
https://github.com/containers/podman.git
synced 2025-05-21 00:56:36 +08:00
Add podman rm --depend
This option causes Podman to not only remove the specified containers but all of the containers that depend on the specified containers. Fixes: https://github.com/containers/podman/issues/10360 Also ran codespell on the code Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
This commit is contained in:
@ -61,7 +61,8 @@ func rmFlags(cmd *cobra.Command) {
|
|||||||
|
|
||||||
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all containers")
|
flags.BoolVarP(&rmOptions.All, "all", "a", false, "Remove all containers")
|
||||||
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
|
flags.BoolVarP(&rmOptions.Ignore, "ignore", "i", false, "Ignore errors when a specified container is missing")
|
||||||
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running or unusable container. The default is false")
|
flags.BoolVarP(&rmOptions.Force, "force", "f", false, "Force removal of a running or unusable container")
|
||||||
|
flags.BoolVar(&rmOptions.Depend, "depend", false, "Remove container and all containers that depend on the selected container")
|
||||||
timeFlagName := "time"
|
timeFlagName := "time"
|
||||||
flags.UintVarP(&stopTimeout, timeFlagName, "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
|
flags.UintVarP(&stopTimeout, timeFlagName, "t", containerConfig.Engine.StopTimeout, "Seconds to wait for stop before killing the container")
|
||||||
_ = cmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone)
|
_ = cmd.RegisterFlagCompletionFunc(timeFlagName, completion.AutocompleteNone)
|
||||||
|
@ -137,7 +137,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
|
|||||||
runtimeFlag := cmd.Root().Flags().Lookup("runtime")
|
runtimeFlag := cmd.Root().Flags().Lookup("runtime")
|
||||||
if runtimeFlag == nil {
|
if runtimeFlag == nil {
|
||||||
return errors.Errorf(
|
return errors.Errorf(
|
||||||
"Unexcpected error setting runtime to '%s' for restore",
|
"setting runtime to '%s' for restore",
|
||||||
*runtime,
|
*runtime,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -217,7 +217,7 @@ func persistentPreRunE(cmd *cobra.Command, args []string) error {
|
|||||||
|
|
||||||
context := cmd.Root().LocalFlags().Lookup("context")
|
context := cmd.Root().LocalFlags().Lookup("context")
|
||||||
if context.Value.String() != "default" {
|
if context.Value.String() != "default" {
|
||||||
return errors.New("Podman does not support swarm, the only --context value allowed is \"default\"")
|
return errors.New("podman does not support swarm, the only --context value allowed is \"default\"")
|
||||||
}
|
}
|
||||||
if !registry.IsRemote() {
|
if !registry.IsRemote() {
|
||||||
if cmd.Flag("cpu-profile").Changed {
|
if cmd.Flag("cpu-profile").Changed {
|
||||||
|
@ -27,7 +27,7 @@ func (o OutputErrors) PrintErrors() (lastError error) {
|
|||||||
instead returns a message and we cast it to a new error.
|
instead returns a message and we cast it to a new error.
|
||||||
|
|
||||||
Following function performs parsing on build error and returns
|
Following function performs parsing on build error and returns
|
||||||
exit status which was exepected for this current build
|
exit status which was expected for this current build
|
||||||
*/
|
*/
|
||||||
func ExitCodeFromBuildError(errorMsg string) (int, error) {
|
func ExitCodeFromBuildError(errorMsg string) (int, error) {
|
||||||
if strings.Contains(errorMsg, "exit status") {
|
if strings.Contains(errorMsg, "exit status") {
|
||||||
|
@ -114,7 +114,7 @@ func addPathToRegistry(dir string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Removes all occurences of a directory path from the Windows path stored in the registry
|
// Removes all occurrences of a directory path from the Windows path stored in the registry
|
||||||
func removePathFromRegistry(path string) error {
|
func removePathFromRegistry(path string) error {
|
||||||
k, err := registry.OpenKey(registry.CURRENT_USER, Environment, registry.READ|registry.WRITE)
|
k, err := registry.OpenKey(registry.CURRENT_USER, Environment, registry.READ|registry.WRITE)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -155,7 +155,7 @@ func removePathFromRegistry(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sends a notification message to all top level windows informing them the environmental setings have changed.
|
// Sends a notification message to all top level windows informing them the environmental settings have changed.
|
||||||
// Applications such as the Windows command prompt and powershell will know to stop caching stale values on
|
// Applications such as the Windows command prompt and powershell will know to stop caching stale values on
|
||||||
// subsequent restarts. Since applications block the sender when receiving a message, we set a 3 second timeout
|
// subsequent restarts. Since applications block the sender when receiving a message, we set a 3 second timeout
|
||||||
func broadcastEnvironmentChange() {
|
func broadcastEnvironmentChange() {
|
||||||
|
@ -18,6 +18,10 @@ Running or unusable containers will not be removed without the **-f** option.
|
|||||||
|
|
||||||
Remove all containers. Can be used in conjunction with **-f** as well.
|
Remove all containers. Can be used in conjunction with **-f** as well.
|
||||||
|
|
||||||
|
#### **--depend**
|
||||||
|
|
||||||
|
Remove selected container and recursively remove all containers that depend on it.
|
||||||
|
|
||||||
#### **--cidfile**
|
#### **--cidfile**
|
||||||
|
|
||||||
Read container ID from the specified file and remove the container. Can be specified multiple times.
|
Read container ID from the specified file and remove the container. Can be specified multiple times.
|
||||||
@ -56,6 +60,11 @@ Remove a container by its name *mywebserver*
|
|||||||
$ podman rm mywebserver
|
$ podman rm mywebserver
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Remove a *mywebserver* container and all of the containers that depend on it
|
||||||
|
```
|
||||||
|
$ podman rm --depend mywebserver
|
||||||
|
```
|
||||||
|
|
||||||
Remove several containers by name and container id.
|
Remove several containers by name and container id.
|
||||||
```
|
```
|
||||||
$ podman rm mywebserver myflaskserver 860a4b23
|
$ podman rm mywebserver myflaskserver 860a4b23
|
||||||
|
@ -915,6 +915,37 @@ func (r *Runtime) evictContainer(ctx context.Context, idOrName string, removeVol
|
|||||||
return id, cleanupErr
|
return id, cleanupErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RemoveDepend removes all dependencies for a container
|
||||||
|
func (r *Runtime) RemoveDepend(ctx context.Context, rmCtr *Container, force bool, removeVolume bool, timeout *uint) ([]*reports.RmReport, error) {
|
||||||
|
rmReports := make([]*reports.RmReport, 0)
|
||||||
|
deps, err := r.state.ContainerInUse(rmCtr)
|
||||||
|
if err != nil {
|
||||||
|
if err == define.ErrCtrRemoved {
|
||||||
|
return rmReports, nil
|
||||||
|
}
|
||||||
|
return rmReports, err
|
||||||
|
}
|
||||||
|
for _, cid := range deps {
|
||||||
|
ctr, err := r.state.Container(cid)
|
||||||
|
if err != nil {
|
||||||
|
if err == define.ErrNoSuchCtr {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
return rmReports, err
|
||||||
|
}
|
||||||
|
|
||||||
|
reports, err := r.RemoveDepend(ctx, ctr, force, removeVolume, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return rmReports, err
|
||||||
|
}
|
||||||
|
rmReports = append(rmReports, reports...)
|
||||||
|
}
|
||||||
|
report := reports.RmReport{Id: rmCtr.ID()}
|
||||||
|
report.Err = r.removeContainer(ctx, rmCtr, force, removeVolume, false, timeout)
|
||||||
|
|
||||||
|
return append(rmReports, &report), nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetContainer retrieves a container by its ID
|
// GetContainer retrieves a container by its ID
|
||||||
func (r *Runtime) GetContainer(id string) (*Container, error) {
|
func (r *Runtime) GetContainer(id string) (*Container, error) {
|
||||||
r.lock.RLock()
|
r.lock.RLock()
|
||||||
|
@ -36,6 +36,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
query := struct {
|
query := struct {
|
||||||
Force bool `schema:"force"`
|
Force bool `schema:"force"`
|
||||||
Ignore bool `schema:"ignore"`
|
Ignore bool `schema:"ignore"`
|
||||||
|
Depend bool `schema:"depend"`
|
||||||
Link bool `schema:"link"`
|
Link bool `schema:"link"`
|
||||||
Timeout *uint `schema:"timeout"`
|
Timeout *uint `schema:"timeout"`
|
||||||
DockerVolumes bool `schema:"v"`
|
DockerVolumes bool `schema:"v"`
|
||||||
@ -57,6 +58,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
if utils.IsLibpodRequest(r) {
|
if utils.IsLibpodRequest(r) {
|
||||||
options.Volumes = query.LibpodVolumes
|
options.Volumes = query.LibpodVolumes
|
||||||
options.Timeout = query.Timeout
|
options.Timeout = query.Timeout
|
||||||
|
options.Depend = query.Depend
|
||||||
} else {
|
} else {
|
||||||
if query.Link {
|
if query.Link {
|
||||||
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
utils.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest,
|
||||||
@ -71,7 +73,7 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
// code.
|
// code.
|
||||||
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
containerEngine := abi.ContainerEngine{Libpod: runtime}
|
||||||
name := utils.GetName(r)
|
name := utils.GetName(r)
|
||||||
report, err := containerEngine.ContainerRm(r.Context(), []string{name}, options)
|
reports, err := containerEngine.ContainerRm(r.Context(), []string{name}, options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
@ -81,8 +83,8 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(report) > 0 && report[0].Err != nil {
|
if len(reports) > 0 && reports[0].Err != nil {
|
||||||
err = report[0].Err
|
err = reports[0].Err
|
||||||
if errors.Cause(err) == define.ErrNoSuchCtr {
|
if errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
utils.ContainerNotFound(w, name, err)
|
utils.ContainerNotFound(w, name, err)
|
||||||
return
|
return
|
||||||
@ -90,7 +92,10 @@ func RemoveContainer(w http.ResponseWriter, r *http.Request) {
|
|||||||
utils.InternalServerError(w, err)
|
utils.InternalServerError(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if utils.IsLibpodRequest(r) {
|
||||||
|
utils.WriteResponse(w, http.StatusOK, reports)
|
||||||
|
return
|
||||||
|
}
|
||||||
utils.WriteResponse(w, http.StatusNoContent, nil)
|
utils.WriteResponse(w, http.StatusNoContent, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +138,7 @@ func BuildImage(w http.ResponseWriter, r *http.Request) {
|
|||||||
|
|
||||||
// if layers field not set assume its not from a valid podman-client
|
// if layers field not set assume its not from a valid podman-client
|
||||||
// could be a docker client, set `layers=true` since that is the default
|
// could be a docker client, set `layers=true` since that is the default
|
||||||
// expected behviour
|
// expected behaviour
|
||||||
if !utils.IsLibpodRequest(r) {
|
if !utils.IsLibpodRequest(r) {
|
||||||
if _, found := r.URL.Query()["layers"]; !found {
|
if _, found := r.URL.Query()["layers"]; !found {
|
||||||
query.Layers = true
|
query.Layers = true
|
||||||
|
@ -111,6 +111,13 @@ type swagLibpodInspectImageResponse struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Rm containers
|
||||||
|
// swagger:response DocsLibpodContainerRmReport
|
||||||
|
type swagLibpodContainerRmReport struct {
|
||||||
|
// in: body
|
||||||
|
Body []handlers.LibpodContainersRmReport
|
||||||
|
}
|
||||||
|
|
||||||
// Prune containers
|
// Prune containers
|
||||||
// swagger:response DocsContainerPruneReport
|
// swagger:response DocsContainerPruneReport
|
||||||
type swagContainerPruneReport struct {
|
type swagContainerPruneReport struct {
|
||||||
|
@ -53,6 +53,17 @@ type LibpodContainersPruneReport struct {
|
|||||||
PruneError string `json:"Err,omitempty"`
|
PruneError string `json:"Err,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LibpodContainersRmReport struct {
|
||||||
|
ID string `json:"Id"`
|
||||||
|
// Error which occurred during Rm operation (if any).
|
||||||
|
// This field is optional and may be omitted if no error occurred.
|
||||||
|
//
|
||||||
|
// Extensions:
|
||||||
|
// x-omitempty: true
|
||||||
|
// x-nullable: true
|
||||||
|
RmError string `json:"Err,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
type Info struct {
|
type Info struct {
|
||||||
docker.Info
|
docker.Info
|
||||||
BuildahVersion string
|
BuildahVersion string
|
||||||
|
@ -817,9 +817,22 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// required: true
|
// required: true
|
||||||
// description: the name or ID of the container
|
// description: the name or ID of the container
|
||||||
// - in: query
|
// - in: query
|
||||||
|
// name: depend
|
||||||
|
// type: boolean
|
||||||
|
// description: additionally remove containers that depend on the container to be removed
|
||||||
|
// - in: query
|
||||||
// name: force
|
// name: force
|
||||||
// type: boolean
|
// type: boolean
|
||||||
// description: need something
|
// description: force stop container if running
|
||||||
|
// - in: query
|
||||||
|
// name: ignore
|
||||||
|
// type: boolean
|
||||||
|
// description: ignore errors when the container to be removed does not existxo
|
||||||
|
// - in: query
|
||||||
|
// name: timeout
|
||||||
|
// type: integer
|
||||||
|
// default: 10
|
||||||
|
// description: number of seconds to wait before killing container when force removing
|
||||||
// - in: query
|
// - in: query
|
||||||
// name: v
|
// name: v
|
||||||
// type: boolean
|
// type: boolean
|
||||||
@ -827,6 +840,8 @@ func (s *APIServer) registerContainersHandlers(r *mux.Router) error {
|
|||||||
// produces:
|
// produces:
|
||||||
// - application/json
|
// - application/json
|
||||||
// responses:
|
// responses:
|
||||||
|
// 200:
|
||||||
|
// $ref: "#/responses/DocsLibpodContainerRmReport"
|
||||||
// 204:
|
// 204:
|
||||||
// description: no error
|
// description: no error
|
||||||
// 400:
|
// 400:
|
||||||
|
@ -78,25 +78,26 @@ func Prune(ctx context.Context, options *PruneOptions) ([]*reports.PruneReport,
|
|||||||
// The volumes bool dictates that a container's volumes should also be removed.
|
// The volumes bool dictates that a container's volumes should also be removed.
|
||||||
// The All option indicates that all containers should be removed
|
// The All option indicates that all containers should be removed
|
||||||
// The Ignore option indicates that if a container did not exist, ignore the error
|
// The Ignore option indicates that if a container did not exist, ignore the error
|
||||||
func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) error {
|
func Remove(ctx context.Context, nameOrID string, options *RemoveOptions) ([]*reports.RmReport, error) {
|
||||||
if options == nil {
|
if options == nil {
|
||||||
options = new(RemoveOptions)
|
options = new(RemoveOptions)
|
||||||
}
|
}
|
||||||
|
var reports []*reports.RmReport
|
||||||
conn, err := bindings.GetClient(ctx)
|
conn, err := bindings.GetClient(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return reports, err
|
||||||
}
|
}
|
||||||
params, err := options.ToParams()
|
params, err := options.ToParams()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return reports, err
|
||||||
}
|
}
|
||||||
response, err := conn.DoRequest(ctx, nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
|
response, err := conn.DoRequest(ctx, nil, http.MethodDelete, "/containers/%s", params, nil, nameOrID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return reports, err
|
||||||
}
|
}
|
||||||
defer response.Body.Close()
|
defer response.Body.Close()
|
||||||
|
|
||||||
return response.Process(nil)
|
return reports, response.Process(&reports)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inspect returns low level information about a Container. The nameOrID can be a container name
|
// Inspect returns low level information about a Container. The nameOrID can be a container name
|
||||||
|
@ -138,6 +138,7 @@ type PruneOptions struct {
|
|||||||
//go:generate go run ../generator/generator.go RemoveOptions
|
//go:generate go run ../generator/generator.go RemoveOptions
|
||||||
// RemoveOptions are optional options for removing containers
|
// RemoveOptions are optional options for removing containers
|
||||||
type RemoveOptions struct {
|
type RemoveOptions struct {
|
||||||
|
Depend *bool
|
||||||
Ignore *bool
|
Ignore *bool
|
||||||
Force *bool
|
Force *bool
|
||||||
Volumes *bool
|
Volumes *bool
|
||||||
|
@ -17,6 +17,21 @@ func (o *RemoveOptions) ToParams() (url.Values, error) {
|
|||||||
return util.ToParams(o)
|
return util.ToParams(o)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithDepend set field Depend to given value
|
||||||
|
func (o *RemoveOptions) WithDepend(value bool) *RemoveOptions {
|
||||||
|
o.Depend = &value
|
||||||
|
return o
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetDepend returns value of field Depend
|
||||||
|
func (o *RemoveOptions) GetDepend() bool {
|
||||||
|
if o.Depend == nil {
|
||||||
|
var z bool
|
||||||
|
return z
|
||||||
|
}
|
||||||
|
return *o.Depend
|
||||||
|
}
|
||||||
|
|
||||||
// WithIgnore set field Ignore to given value
|
// WithIgnore set field Ignore to given value
|
||||||
func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
|
func (o *RemoveOptions) WithIgnore(value bool) *RemoveOptions {
|
||||||
o.Ignore = &value
|
o.Ignore = &value
|
||||||
|
@ -175,7 +175,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Pause(bt.conn, cid, nil)
|
err = containers.Pause(bt.conn, cid, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Remove(bt.conn, cid, nil)
|
_, err = containers.Remove(bt.conn, cid, nil)
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||||
@ -188,8 +188,10 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Pause(bt.conn, cid, nil)
|
err = containers.Pause(bt.conn, cid, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
|
rmResponse, err := containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
Expect(len(reports.RmReportsErrs(rmResponse))).To(Equal(0))
|
||||||
|
Expect(len(reports.RmReportsIds(rmResponse))).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman stop a paused container by name", func() {
|
It("podman stop a paused container by name", func() {
|
||||||
@ -669,7 +671,8 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
})
|
})
|
||||||
|
|
||||||
It("podman remove bogus container", func() {
|
It("podman remove bogus container", func() {
|
||||||
err = containers.Remove(bt.conn, "foobar", nil)
|
_, err := containers.Remove(bt.conn, "foobar", nil)
|
||||||
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusNotFound))
|
Expect(code).To(BeNumerically("==", http.StatusNotFound))
|
||||||
})
|
})
|
||||||
@ -679,7 +682,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
_, err := bt.RunTopContainer(&name, nil)
|
_, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Removing running container should fail
|
||||||
err = containers.Remove(bt.conn, name, nil)
|
_, err = containers.Remove(bt.conn, name, nil)
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||||
@ -690,7 +693,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
cid, err := bt.RunTopContainer(&name, nil)
|
cid, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Removing running container should fail
|
||||||
err = containers.Remove(bt.conn, cid, nil)
|
_, err = containers.Remove(bt.conn, cid, nil)
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||||
@ -700,22 +703,22 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
var name = "top"
|
var name = "top"
|
||||||
_, err := bt.RunTopContainer(&name, nil)
|
_, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Removing running container should succeed
|
||||||
err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithForce(true))
|
rmResponse, err := containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithForce(true))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
//code, _ := bindings.CheckResponseCode(err)
|
Expect(len(reports.RmReportsErrs(rmResponse))).To(Equal(0))
|
||||||
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(len(reports.RmReportsIds(rmResponse))).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman forcibly remove running container by ID", func() {
|
It("podman forcibly remove running container by ID", func() {
|
||||||
var name = "top"
|
var name = "top"
|
||||||
cid, err := bt.RunTopContainer(&name, nil)
|
cid, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Forcably Removing running container should succeed
|
||||||
err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
|
rmResponse, err := containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
//code, _ := bindings.CheckResponseCode(err)
|
Expect(len(reports.RmReportsErrs(rmResponse))).To(Equal(0))
|
||||||
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(len(reports.RmReportsIds(rmResponse))).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman remove running container and volume by name", func() {
|
It("podman remove running container and volume by name", func() {
|
||||||
@ -723,7 +726,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
_, err := bt.RunTopContainer(&name, nil)
|
_, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Removing running container should fail
|
||||||
err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true))
|
_, err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true))
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||||
@ -734,7 +737,7 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
cid, err := bt.RunTopContainer(&name, nil)
|
cid, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Removing running container should fail
|
||||||
err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithVolumes(true))
|
_, err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithVolumes(true))
|
||||||
Expect(err).ToNot(BeNil())
|
Expect(err).ToNot(BeNil())
|
||||||
code, _ := bindings.CheckResponseCode(err)
|
code, _ := bindings.CheckResponseCode(err)
|
||||||
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
||||||
@ -744,11 +747,11 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
var name = "top"
|
var name = "top"
|
||||||
_, err := bt.RunTopContainer(&name, nil)
|
_, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Forcibly Removing running container should succeed
|
||||||
err = containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true).WithForce(true))
|
rmResponse, err := containers.Remove(bt.conn, name, new(containers.RemoveOptions).WithVolumes(true).WithForce(true))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
//code, _ := bindings.CheckResponseCode(err)
|
Expect(len(reports.RmReportsErrs(rmResponse))).To(Equal(0))
|
||||||
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(len(reports.RmReportsIds(rmResponse))).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("podman forcibly remove running container and volume by ID", func() {
|
It("podman forcibly remove running container and volume by ID", func() {
|
||||||
@ -756,10 +759,10 @@ var _ = Describe("Podman containers ", func() {
|
|||||||
cid, err := bt.RunTopContainer(&name, nil)
|
cid, err := bt.RunTopContainer(&name, nil)
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
// Removing running container should fail
|
// Removing running container should fail
|
||||||
err = containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true).WithVolumes(true))
|
rmResponse, err := containers.Remove(bt.conn, cid, new(containers.RemoveOptions).WithForce(true).WithVolumes(true))
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
//code, _ := bindings.CheckResponseCode(err)
|
Expect(len(reports.RmReportsErrs(rmResponse))).To(Equal(0))
|
||||||
//Expect(code).To(BeNumerically("==", http.StatusInternalServerError))
|
Expect(len(reports.RmReportsIds(rmResponse))).To(Equal(1))
|
||||||
})
|
})
|
||||||
|
|
||||||
It("List containers with filters", func() {
|
It("List containers with filters", func() {
|
||||||
|
@ -129,6 +129,7 @@ type RestartReport struct {
|
|||||||
|
|
||||||
type RmOptions struct {
|
type RmOptions struct {
|
||||||
All bool
|
All bool
|
||||||
|
Depend bool
|
||||||
Force bool
|
Force bool
|
||||||
Ignore bool
|
Ignore bool
|
||||||
Latest bool
|
Latest bool
|
||||||
@ -136,11 +137,6 @@ type RmOptions struct {
|
|||||||
Volumes bool
|
Volumes bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type RmReport struct {
|
|
||||||
Err error
|
|
||||||
Id string //nolint
|
|
||||||
}
|
|
||||||
|
|
||||||
type ContainerInspectReport struct {
|
type ContainerInspectReport struct {
|
||||||
*define.InspectContainerData
|
*define.InspectContainerData
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ type ContainerEngine interface {
|
|||||||
ContainerRename(ctr context.Context, nameOrID string, options ContainerRenameOptions) error
|
ContainerRename(ctr context.Context, nameOrID string, options ContainerRenameOptions) error
|
||||||
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
|
ContainerRestart(ctx context.Context, namesOrIds []string, options RestartOptions) ([]*RestartReport, error)
|
||||||
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
|
ContainerRestore(ctx context.Context, namesOrIds []string, options RestoreOptions) ([]*RestoreReport, error)
|
||||||
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*RmReport, error)
|
ContainerRm(ctx context.Context, namesOrIds []string, options RmOptions) ([]*reports.RmReport, error)
|
||||||
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
|
ContainerRun(ctx context.Context, opts ContainerRunOptions) (*ContainerRunReport, error)
|
||||||
ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
|
ContainerRunlabel(ctx context.Context, label string, image string, args []string, opts ContainerRunlabelOptions) error
|
||||||
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
|
ContainerStart(ctx context.Context, namesOrIds []string, options ContainerStartOptions) ([]*ContainerStartReport, error)
|
||||||
|
28
pkg/domain/entities/reports/containers.go
Normal file
28
pkg/domain/entities/reports/containers.go
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
package reports
|
||||||
|
|
||||||
|
type RmReport struct {
|
||||||
|
Id string `json:"Id"` //nolint
|
||||||
|
Err error `json:"Err,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func RmReportsIds(r []*RmReport) []string {
|
||||||
|
ids := make([]string, 0, len(r))
|
||||||
|
for _, v := range r {
|
||||||
|
if v == nil || v.Id == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ids = append(ids, v.Id)
|
||||||
|
}
|
||||||
|
return ids
|
||||||
|
}
|
||||||
|
|
||||||
|
func RmReportsErrs(r []*RmReport) []error {
|
||||||
|
errs := make([]error, 0, len(r))
|
||||||
|
for _, v := range r {
|
||||||
|
if v == nil || v.Err == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
errs = append(errs, v.Err)
|
||||||
|
}
|
||||||
|
return errs
|
||||||
|
}
|
@ -301,27 +301,27 @@ func (ic *ContainerEngine) removeContainer(ctx context.Context, ctr *libpod.Cont
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*entities.RmReport, error) {
|
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, options entities.RmOptions) ([]*reports.RmReport, error) {
|
||||||
reports := []*entities.RmReport{}
|
rmReports := []*reports.RmReport{}
|
||||||
|
|
||||||
names := namesOrIds
|
names := namesOrIds
|
||||||
// Attempt to remove named containers directly from storage, if container is defined in libpod
|
// Attempt to remove named containers directly from storage, if container is defined in libpod
|
||||||
// this will fail and code will fall through to removing the container from libpod.`
|
// this will fail and code will fall through to removing the container from libpod.`
|
||||||
tmpNames := []string{}
|
tmpNames := []string{}
|
||||||
for _, ctr := range names {
|
for _, ctr := range names {
|
||||||
report := entities.RmReport{Id: ctr}
|
report := reports.RmReport{Id: ctr}
|
||||||
report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force)
|
report.Err = ic.Libpod.RemoveStorageContainer(ctr, options.Force)
|
||||||
switch errors.Cause(report.Err) {
|
switch errors.Cause(report.Err) {
|
||||||
case nil:
|
case nil:
|
||||||
// remove container names that we successfully deleted
|
// remove container names that we successfully deleted
|
||||||
reports = append(reports, &report)
|
rmReports = append(rmReports, &report)
|
||||||
case define.ErrNoSuchCtr, define.ErrCtrExists:
|
case define.ErrNoSuchCtr, define.ErrCtrExists:
|
||||||
// There is still a potential this is a libpod container
|
// There is still a potential this is a libpod container
|
||||||
tmpNames = append(tmpNames, ctr)
|
tmpNames = append(tmpNames, ctr)
|
||||||
default:
|
default:
|
||||||
if _, err := ic.Libpod.LookupContainer(ctr); errors.Cause(err) == define.ErrNoSuchCtr {
|
if _, err := ic.Libpod.LookupContainer(ctr); errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
// remove container failed, but not a libpod container
|
// remove container failed, but not a libpod container
|
||||||
reports = append(reports, &report)
|
rmReports = append(rmReports, &report)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// attempt to remove as a libpod container
|
// attempt to remove as a libpod container
|
||||||
@ -340,23 +340,34 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
|
|||||||
|
|
||||||
for _, ctr := range names {
|
for _, ctr := range names {
|
||||||
logrus.Debugf("Evicting container %q", ctr)
|
logrus.Debugf("Evicting container %q", ctr)
|
||||||
report := entities.RmReport{Id: ctr}
|
report := reports.RmReport{Id: ctr}
|
||||||
_, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
|
_, err := ic.Libpod.EvictContainer(ctx, ctr, options.Volumes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
|
if options.Ignore && errors.Cause(err) == define.ErrNoSuchCtr {
|
||||||
logrus.Debugf("Ignoring error (--allow-missing): %v", err)
|
logrus.Debugf("Ignoring error (--allow-missing): %v", err)
|
||||||
reports = append(reports, &report)
|
rmReports = append(rmReports, &report)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
report.Err = err
|
report.Err = err
|
||||||
reports = append(reports, &report)
|
rmReports = append(rmReports, &report)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
reports = append(reports, &report)
|
rmReports = append(rmReports, &report)
|
||||||
}
|
}
|
||||||
return reports, nil
|
return rmReports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !options.All && options.Depend {
|
||||||
|
// Add additional containers based on dependencies to container map
|
||||||
|
for _, ctr := range ctrs {
|
||||||
|
reports, err := ic.Libpod.RemoveDepend(ctx, ctr, options.Force, options.Volumes, options.Timeout)
|
||||||
|
if err != nil {
|
||||||
|
return rmReports, err
|
||||||
|
}
|
||||||
|
rmReports = append(rmReports, reports...)
|
||||||
|
}
|
||||||
|
return rmReports, nil
|
||||||
|
}
|
||||||
errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
|
errMap, err := parallelctr.ContainerOp(ctx, ctrs, func(c *libpod.Container) error {
|
||||||
return ic.removeContainer(ctx, c, options)
|
return ic.removeContainer(ctx, c, options)
|
||||||
})
|
})
|
||||||
@ -364,12 +375,12 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for ctr, err := range errMap {
|
for ctr, err := range errMap {
|
||||||
report := new(entities.RmReport)
|
report := new(reports.RmReport)
|
||||||
report.Id = ctr.ID()
|
report.Id = ctr.ID()
|
||||||
report.Err = err
|
report.Err = err
|
||||||
reports = append(reports, report)
|
rmReports = append(rmReports, report)
|
||||||
}
|
}
|
||||||
return reports, nil
|
return rmReports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
|
func (ic *ContainerEngine) ContainerInspect(ctx context.Context, namesOrIds []string, options entities.InspectOptions) ([]*entities.ContainerInspectReport, []error, error) {
|
||||||
|
@ -182,9 +182,9 @@ func (ic *ContainerEngine) ContainerRestart(ctx context.Context, namesOrIds []st
|
|||||||
return reports, nil
|
return reports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*entities.RmReport, error) {
|
func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string, opts entities.RmOptions) ([]*reports.RmReport, error) {
|
||||||
// TODO there is no endpoint for container eviction. Need to discuss
|
// TODO there is no endpoint for container eviction. Need to discuss
|
||||||
options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes).WithIgnore(opts.Ignore)
|
options := new(containers.RemoveOptions).WithForce(opts.Force).WithVolumes(opts.Volumes).WithIgnore(opts.Ignore).WithDepend(opts.Depend)
|
||||||
if opts.Timeout != nil {
|
if opts.Timeout != nil {
|
||||||
options = options.WithTimeout(*opts.Timeout)
|
options = options.WithTimeout(*opts.Timeout)
|
||||||
}
|
}
|
||||||
@ -193,25 +193,31 @@ func (ic *ContainerEngine) ContainerRm(ctx context.Context, namesOrIds []string,
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
reports := make([]*entities.RmReport, 0, len(ctrs))
|
rmReports := make([]*reports.RmReport, 0, len(ctrs))
|
||||||
for _, c := range ctrs {
|
for _, c := range ctrs {
|
||||||
reports = append(reports, &entities.RmReport{
|
report, err := containers.Remove(ic.ClientCtx, c.ID, options)
|
||||||
Id: c.ID,
|
if err != nil {
|
||||||
Err: containers.Remove(ic.ClientCtx, c.ID, options),
|
return rmReports, err
|
||||||
})
|
}
|
||||||
|
rmReports = append(rmReports, report...)
|
||||||
}
|
}
|
||||||
return reports, nil
|
return rmReports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
reports := make([]*entities.RmReport, 0, len(namesOrIds))
|
rmReports := make([]*reports.RmReport, 0, len(namesOrIds))
|
||||||
for _, name := range namesOrIds {
|
for _, name := range namesOrIds {
|
||||||
reports = append(reports, &entities.RmReport{
|
report, err := containers.Remove(ic.ClientCtx, name, options)
|
||||||
Id: name,
|
if err != nil {
|
||||||
Err: containers.Remove(ic.ClientCtx, name, options),
|
rmReports = append(rmReports, &reports.RmReport{
|
||||||
})
|
Id: name,
|
||||||
|
Err: err,
|
||||||
|
})
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
rmReports = append(rmReports, report...)
|
||||||
}
|
}
|
||||||
|
|
||||||
return reports, nil
|
return rmReports, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
|
func (ic *ContainerEngine) ContainerPrune(ctx context.Context, opts entities.ContainerPruneOptions) ([]*reports.PruneReport, error) {
|
||||||
@ -552,6 +558,27 @@ func startAndAttach(ic *ContainerEngine, name string, detachKeys *string, input,
|
|||||||
return <-attachErr
|
return <-attachErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func logIfRmError(id string, err error, reports []*reports.RmReport) {
|
||||||
|
logError := func(id string, err error) {
|
||||||
|
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
|
||||||
|
errorhandling.Contains(err, define.ErrCtrRemoved) ||
|
||||||
|
errorhandling.Contains(err, types.ErrLayerUnknown) {
|
||||||
|
logrus.Debugf("Container %s does not exist: %v", id, err)
|
||||||
|
} else {
|
||||||
|
logrus.Errorf("Removing container %s: %v", id, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
logError(id, err)
|
||||||
|
} else {
|
||||||
|
for _, report := range reports {
|
||||||
|
if report.Err != nil {
|
||||||
|
logError(report.Id, report.Err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
|
func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []string, options entities.ContainerStartOptions) ([]*entities.ContainerStartReport, error) {
|
||||||
reports := []*entities.ContainerStartReport{}
|
reports := []*entities.ContainerStartReport{}
|
||||||
var exitCode = define.ExecErrorCodeGeneric
|
var exitCode = define.ExecErrorCodeGeneric
|
||||||
@ -590,14 +617,8 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
|
|||||||
}
|
}
|
||||||
removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(false)
|
removeOptions := new(containers.RemoveOptions).WithVolumes(true).WithForce(false)
|
||||||
removeContainer := func(id string) {
|
removeContainer := func(id string) {
|
||||||
if err := containers.Remove(ic.ClientCtx, id, removeOptions); err != nil {
|
reports, err := containers.Remove(ic.ClientCtx, id, removeOptions)
|
||||||
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
|
logIfRmError(id, err, reports)
|
||||||
errorhandling.Contains(err, define.ErrCtrRemoved) {
|
|
||||||
logrus.Debugf("Container %s does not exist: %v", id, err)
|
|
||||||
} else {
|
|
||||||
logrus.Errorf("Removing container %s: %v", id, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// There can only be one container if attach was used
|
// There can only be one container if attach was used
|
||||||
@ -674,15 +695,8 @@ func (ic *ContainerEngine) ContainerStart(ctx context.Context, namesOrIds []stri
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if ctr.AutoRemove {
|
if ctr.AutoRemove {
|
||||||
rmOptions := new(containers.RemoveOptions).WithForce(false).WithVolumes(true)
|
rmOptions := new(containers.RemoveOptions).WithForce(false).WithVolumes(true)
|
||||||
if err := containers.Remove(ic.ClientCtx, ctr.ID, rmOptions); err != nil {
|
reports, err := containers.Remove(ic.ClientCtx, ctr.ID, rmOptions)
|
||||||
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
|
logIfRmError(ctr.ID, err, reports)
|
||||||
errorhandling.Contains(err, define.ErrCtrRemoved) ||
|
|
||||||
errorhandling.Contains(err, types.ErrLayerUnknown) {
|
|
||||||
logrus.Debugf("Container %s does not exist: %v", ctr.ID, err)
|
|
||||||
} else {
|
|
||||||
logrus.Errorf("Removing container %s: %v", ctr.ID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
report.Err = errors.Wrapf(err, "unable to start container %q", name)
|
report.Err = errors.Wrapf(err, "unable to start container %q", name)
|
||||||
report.ExitCode = define.ExitCode(err)
|
report.ExitCode = define.ExitCode(err)
|
||||||
@ -741,7 +755,8 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
|||||||
|
|
||||||
report.ExitCode = define.ExitCode(err)
|
report.ExitCode = define.ExitCode(err)
|
||||||
if opts.Rm {
|
if opts.Rm {
|
||||||
if rmErr := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); rmErr != nil {
|
reports, rmErr := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true))
|
||||||
|
if rmErr != nil || reports[0].Err != nil {
|
||||||
logrus.Debugf("unable to remove container %s after failing to start and attach to it", con.ID)
|
logrus.Debugf("unable to remove container %s after failing to start and attach to it", con.ID)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -759,15 +774,8 @@ func (ic *ContainerEngine) ContainerRun(ctx context.Context, opts entities.Conta
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !shouldRestart {
|
if !shouldRestart {
|
||||||
if err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true)); err != nil {
|
reports, err := containers.Remove(ic.ClientCtx, con.ID, new(containers.RemoveOptions).WithForce(false).WithVolumes(true))
|
||||||
if errorhandling.Contains(err, define.ErrNoSuchCtr) ||
|
logIfRmError(con.ID, err, reports)
|
||||||
errorhandling.Contains(err, define.ErrCtrRemoved) ||
|
|
||||||
errorhandling.Contains(err, types.ErrLayerUnknown) {
|
|
||||||
logrus.Debugf("Container %s does not exist: %v", con.ID, err)
|
|
||||||
} else {
|
|
||||||
logrus.Errorf("Removing container %s: %v", con.ID, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ func ParsePortMapping(portMappings []types.PortMapping, exposePorts map[uint16][
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we do no longer need the original port mappings
|
// we do no longer need the original port mappings
|
||||||
// set it to 0 length so we can resuse it to populate
|
// set it to 0 length so we can reuse it to populate
|
||||||
// the slice again while keeping the underlying capacity
|
// the slice again while keeping the underlying capacity
|
||||||
portMappings = portMappings[:0]
|
portMappings = portMappings[:0]
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ type PodNetworkConfig struct {
|
|||||||
// Map of networks names ot ids the container should join to.
|
// Map of networks names ot ids the container should join to.
|
||||||
// You can request additional settings for each network, you can
|
// You can request additional settings for each network, you can
|
||||||
// set network aliases, static ips, static mac address and the
|
// set network aliases, static ips, static mac address and the
|
||||||
// network interface name for this container on the specifc network.
|
// network interface name for this container on the specific network.
|
||||||
// If the map is empty and the bridge network mode is set the container
|
// If the map is empty and the bridge network mode is set the container
|
||||||
// will be joined to the default network.
|
// will be joined to the default network.
|
||||||
Networks map[string]types.PerNetworkOptions
|
Networks map[string]types.PerNetworkOptions
|
||||||
|
@ -426,7 +426,7 @@ type ContainerNetworkConfig struct {
|
|||||||
// Map of networks names ot ids the container should join to.
|
// Map of networks names ot ids the container should join to.
|
||||||
// You can request additional settings for each network, you can
|
// You can request additional settings for each network, you can
|
||||||
// set network aliases, static ips, static mac address and the
|
// set network aliases, static ips, static mac address and the
|
||||||
// network interface name for this container on the specifc network.
|
// network interface name for this container on the specific network.
|
||||||
// If the map is empty and the bridge network mode is set the container
|
// If the map is empty and the bridge network mode is set the container
|
||||||
// will be joined to the default network.
|
// will be joined to the default network.
|
||||||
Networks map[string]nettypes.PerNetworkOptions
|
Networks map[string]nettypes.PerNetworkOptions
|
||||||
|
@ -53,7 +53,7 @@ t GET libpod/images/$IMAGE/json 200 \
|
|||||||
.RepoTags[-1]=$IMAGE
|
.RepoTags[-1]=$IMAGE
|
||||||
|
|
||||||
# Remove the registry container
|
# Remove the registry container
|
||||||
t DELETE libpod/containers/registry?force=true 204
|
t DELETE libpod/containers/registry?force=true 200
|
||||||
|
|
||||||
# Remove images
|
# Remove images
|
||||||
t DELETE libpod/images/$IMAGE 200 \
|
t DELETE libpod/images/$IMAGE 200 \
|
||||||
|
@ -85,7 +85,7 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
t DELETE libpod/containers/$cid 204
|
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
|
||||||
|
|
||||||
# Issue #6799: it should be possible to start a container, even w/o args.
|
# Issue #6799: it should be possible to start a container, even w/o args.
|
||||||
t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
|
t POST libpod/containers/create?name=test_noargs Image=${IMAGE} 201 \
|
||||||
@ -100,7 +100,7 @@ t GET libpod/containers/${cid}/json 200 \
|
|||||||
.State.Status~\\\(exited\\\|stopped\\\) \
|
.State.Status~\\\(exited\\\|stopped\\\) \
|
||||||
.State.Running=false \
|
.State.Running=false \
|
||||||
.State.ExitCode=0
|
.State.ExitCode=0
|
||||||
t DELETE libpod/containers/$cid 204
|
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
|
||||||
|
|
||||||
CNAME=myfoo
|
CNAME=myfoo
|
||||||
podman run -d --name $CNAME $IMAGE top
|
podman run -d --name $CNAME $IMAGE top
|
||||||
@ -190,8 +190,8 @@ t GET containers/myctr/json 200 \
|
|||||||
t DELETE images/localhost/newrepo:latest?force=true 200
|
t DELETE images/localhost/newrepo:latest?force=true 200
|
||||||
t DELETE images/localhost/newrepo:v1?force=true 200
|
t DELETE images/localhost/newrepo:v1?force=true 200
|
||||||
t DELETE images/localhost/newrepo:v2?force=true 200
|
t DELETE images/localhost/newrepo:v2?force=true 200
|
||||||
t DELETE libpod/containers/$cid?force=true 204
|
t DELETE libpod/containers/$cid?force=true 200 .[0].Id=$cid
|
||||||
t DELETE libpod/containers/myctr 204
|
t DELETE libpod/containers/myctr 200
|
||||||
t DELETE libpod/containers/bogus 404
|
t DELETE libpod/containers/bogus 404
|
||||||
|
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ podman run -dt --name mytop $IMAGE top &>/dev/null
|
|||||||
t GET libpod/containers/mytop/json 200 .State.Status=running
|
t GET libpod/containers/mytop/json 200 .State.Status=running
|
||||||
t POST libpod/containers/mytop/stop 204
|
t POST libpod/containers/mytop/stop 204
|
||||||
t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
|
t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
|
||||||
t DELETE libpod/containers/mytop 204
|
t DELETE libpod/containers/mytop 200
|
||||||
|
|
||||||
# stop, by ID
|
# stop, by ID
|
||||||
# Remember that podman() hides all output; we need to get our CID via inspect
|
# Remember that podman() hides all output; we need to get our CID via inspect
|
||||||
@ -21,4 +21,4 @@ t GET libpod/containers/mytop/json 200 .State.Status=running
|
|||||||
cid=$(jq -r .Id <<<"$output")
|
cid=$(jq -r .Id <<<"$output")
|
||||||
t POST libpod/containers/$cid/stop 204
|
t POST libpod/containers/$cid/stop 204
|
||||||
t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
|
t GET libpod/containers/mytop/json 200 .State.Status~\\\(exited\\\|stopped\\\)
|
||||||
t DELETE libpod/containers/mytop 204
|
t DELETE libpod/containers/mytop 200
|
||||||
|
@ -51,7 +51,7 @@ like "$output" ".*merged" "Check container mount"
|
|||||||
# Unmount the container
|
# Unmount the container
|
||||||
t POST libpod/containers/foo/unmount 204
|
t POST libpod/containers/foo/unmount 204
|
||||||
|
|
||||||
t DELETE libpod/containers/foo?force=true 204
|
t DELETE libpod/containers/foo?force=true 200
|
||||||
|
|
||||||
podman run $IMAGE true
|
podman run $IMAGE true
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ like "$output" ".*metadata:.*" "Check generated kube yaml(service=true) - metada
|
|||||||
like "$output" ".*spec:.*" "Check generated kube yaml(service=true) - spec"
|
like "$output" ".*spec:.*" "Check generated kube yaml(service=true) - spec"
|
||||||
like "$output" ".*kind:\\sService.*" "Check generated kube yaml(service=true) - kind: Service"
|
like "$output" ".*kind:\\sService.*" "Check generated kube yaml(service=true) - kind: Service"
|
||||||
|
|
||||||
t DELETE libpod/containers/$cid 204
|
t DELETE libpod/containers/$cid 200 .[0].Id=$cid
|
||||||
|
|
||||||
# Create 3 stopped containers to test containers prune
|
# Create 3 stopped containers to test containers prune
|
||||||
podman run $IMAGE true
|
podman run $IMAGE true
|
||||||
|
@ -99,7 +99,7 @@ class ContainerTestCase(APITestCase):
|
|||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
r = requests.delete(self.uri(self.resolve_container("/containers/{}?force=true")))
|
r = requests.delete(self.uri(self.resolve_container("/containers/{}?force=true")))
|
||||||
self.assertEqual(r.status_code, 204, r.text)
|
self.assertEqual(r.status_code, 200, r.text)
|
||||||
|
|
||||||
def test_stop(self):
|
def test_stop(self):
|
||||||
r = requests.post(self.uri(self.resolve_container("/containers/{}/start")))
|
r = requests.post(self.uri(self.resolve_container("/containers/{}/start")))
|
||||||
|
@ -41,7 +41,7 @@ function setup() {
|
|||||||
# This one must fail
|
# This one must fail
|
||||||
run_podman 125 --context=swarm version
|
run_podman 125 --context=swarm version
|
||||||
is "$output" \
|
is "$output" \
|
||||||
"Error: Podman does not support swarm, the only --context value allowed is \"default\"" \
|
"Error: podman does not support swarm, the only --context value allowed is \"default\"" \
|
||||||
"--context=default or fail"
|
"--context=default or fail"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,18 @@ load helpers
|
|||||||
run_podman rm -af
|
run_podman rm -af
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@test "podman rm --depend" {
|
||||||
|
run_podman create $IMAGE
|
||||||
|
dependCid=$output
|
||||||
|
run_podman create --net=container:$dependCid $IMAGE
|
||||||
|
cid=$output
|
||||||
|
run_podman 125 rm $dependCid
|
||||||
|
is "$output" "Error: container $dependCid has dependent containers which must be removed before it:.*" "Fail to remove because of dependencies"
|
||||||
|
run_podman rm --depend $dependCid
|
||||||
|
is "$output" ".*$cid" "Container should have been removed"
|
||||||
|
is "$output" ".*$dependCid" "Depend container should have been removed"
|
||||||
|
}
|
||||||
|
|
||||||
# I'm sorry! This test takes 13 seconds. There's not much I can do about it,
|
# I'm sorry! This test takes 13 seconds. There's not much I can do about it,
|
||||||
# please know that I think it's justified: podman 1.5.0 had a strange bug
|
# please know that I think it's justified: podman 1.5.0 had a strange bug
|
||||||
# in with exit status was not preserved on some code paths with 'rm -f'
|
# in with exit status was not preserved on some code paths with 'rm -f'
|
||||||
|
Reference in New Issue
Block a user