@@ -12,6 +12,7 @@ import (
1212 "github.com/containers/image/pkg/sysregistries"
1313 "github.com/containers/image/tarball"
1414 "github.com/containers/image/types"
15+ "github.com/containers/storage"
1516 "github.com/containers/storage/pkg/archive"
1617 ociv1 "github.com/opencontainers/image-spec/specs-go/v1"
1718 "github.com/pkg/errors"
@@ -123,8 +124,61 @@ func (r *Runtime) RemoveImage(image *image.Image, force bool) (string, error) {
123124 // reponames and no force is applied, we error out.
124125 return "" , fmt .Errorf ("unable to delete %s (must force) - image is referred to in multiple tags" , image .ID ())
125126 }
127+ err = image .Remove (force )
128+ if err != nil && errors .Cause (err ) == storage .ErrImageUsedByContainer {
129+ if errStorage := r .rmStorageContainers (force , image ); errStorage == nil {
130+ // Containers associated with the image should be deleted now,
131+ // let's try removing the image again.
132+ err = image .Remove (force )
133+ } else {
134+ err = errStorage
135+ }
136+ }
137+ return image .ID (), err
138+ }
126139
127- return image .ID (), image .Remove (force )
140+ // Remove containers that are in storage rather than Podman.
141+ func (r * Runtime ) rmStorageContainers (force bool , image * image.Image ) error {
142+ ctrIDs , err := storageContainers (image .ID (), r .store )
143+ if err != nil {
144+ return errors .Wrapf (err , "error getting containers for image %q" , image .ID ())
145+ }
146+
147+ if len (ctrIDs ) > 0 && ! force {
148+ return storage .ErrImageUsedByContainer
149+ }
150+
151+ if len (ctrIDs ) > 0 && force {
152+ if err = removeStorageContainers (ctrIDs , r .store ); err != nil {
153+ return errors .Wrapf (err , "error removing containers %v for image %q" , ctrIDs , image .ID ())
154+ }
155+ }
156+ return nil
157+ }
158+
159+ // Returns a list of storage containers associated with the given ImageReference
160+ func storageContainers (imageID string , store storage.Store ) ([]string , error ) {
161+ ctrIDs := []string {}
162+ containers , err := store .Containers ()
163+ if err != nil {
164+ return nil , err
165+ }
166+ for _ , ctr := range containers {
167+ if ctr .ImageID == imageID {
168+ ctrIDs = append (ctrIDs , ctr .ID )
169+ }
170+ }
171+ return ctrIDs , nil
172+ }
173+
174+ // Removes the containers passed in the array.
175+ func removeStorageContainers (ctrIDs []string , store storage.Store ) error {
176+ for _ , ctrID := range ctrIDs {
177+ if err := store .DeleteContainer (ctrID ); err != nil {
178+ return errors .Wrapf (err , "could not remove container %q" , ctrID )
179+ }
180+ }
181+ return nil
128182}
129183
130184// GetRegistries gets the searchable registries from the global registration file.
0 commit comments