Allow untag operations with no container validation
This commit is contained in:
parent
606cacdca0
commit
62213ee314
|
@ -409,3 +409,50 @@ func TestImageInsert(t *testing.T) {
|
||||||
t.Fatalf("expected no error, but got %v", err)
|
t.Fatalf("expected no error, but got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Regression test for being able to untag an image with an existing
|
||||||
|
// container
|
||||||
|
func TestDeleteTagWithExistingContainers(t *testing.T) {
|
||||||
|
eng := NewTestEngine(t)
|
||||||
|
defer nuke(mkRuntimeFromEngine(eng, t))
|
||||||
|
|
||||||
|
srv := mkServerFromEngine(eng, t)
|
||||||
|
|
||||||
|
// Tag the image
|
||||||
|
if err := eng.Job("tag", unitTestImageID, "utest", "tag1").Run(); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a container from the image
|
||||||
|
config, _, _, err := docker.ParseRun([]string{unitTestImageID, "echo test"}, nil)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
id := createNamedTestContainer(eng, config, t, "testingtags")
|
||||||
|
if id == "" {
|
||||||
|
t.Fatal("No id returned")
|
||||||
|
}
|
||||||
|
|
||||||
|
containers := srv.Containers(true, false, -1, "", "")
|
||||||
|
|
||||||
|
if len(containers) != 1 {
|
||||||
|
t.Fatalf("Expected 1 container got %d", len(containers))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to remove the tag
|
||||||
|
imgs, err := srv.ImageDelete("utest:tag1", true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(imgs) != 1 {
|
||||||
|
t.Fatalf("Should only have deleted one untag %d", len(imgs))
|
||||||
|
}
|
||||||
|
|
||||||
|
untag := imgs[0]
|
||||||
|
|
||||||
|
if untag.Untagged != unitTestImageID {
|
||||||
|
t.Fatalf("Expected %s got %s", unitTestImageID, untag.Untagged)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
35
server.go
35
server.go
|
@ -1550,8 +1550,10 @@ func (srv *Server) deleteImageParents(img *Image, imgs *[]APIRmi) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
|
func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, error) {
|
||||||
imgs := []APIRmi{}
|
var (
|
||||||
tags := []string{}
|
imgs = []APIRmi{}
|
||||||
|
tags = []string{}
|
||||||
|
)
|
||||||
|
|
||||||
//If delete by id, see if the id belong only to one repository
|
//If delete by id, see if the id belong only to one repository
|
||||||
if repoName == "" {
|
if repoName == "" {
|
||||||
|
@ -1571,6 +1573,7 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
|
||||||
} else {
|
} else {
|
||||||
tags = append(tags, tag)
|
tags = append(tags, tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
//Untag the current image
|
//Untag the current image
|
||||||
for _, tag := range tags {
|
for _, tag := range tags {
|
||||||
tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
|
tagDeleted, err := srv.runtime.repositories.Delete(repoName, tag)
|
||||||
|
@ -1582,6 +1585,7 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
|
||||||
srv.LogEvent("untag", img.ID, "")
|
srv.LogEvent("untag", img.ID, "")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
|
if len(srv.runtime.repositories.ByID()[img.ID]) == 0 {
|
||||||
if err := srv.deleteImageAndChildren(img.ID, &imgs, nil); err != nil {
|
if err := srv.deleteImageAndChildren(img.ID, &imgs, nil); err != nil {
|
||||||
if err != ErrImageReferenced {
|
if err != ErrImageReferenced {
|
||||||
|
@ -1597,10 +1601,16 @@ func (srv *Server) deleteImage(img *Image, repoName, tag string) ([]APIRmi, erro
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
|
func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
|
||||||
|
var (
|
||||||
|
repository, tag string
|
||||||
|
validate = true
|
||||||
|
)
|
||||||
img, err := srv.runtime.repositories.LookupImage(name)
|
img, err := srv.runtime.repositories.LookupImage(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("No such image: %s", name)
|
return nil, fmt.Errorf("No such image: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: What does autoPrune mean ?
|
||||||
if !autoPrune {
|
if !autoPrune {
|
||||||
if err := srv.runtime.graph.Delete(img.ID); err != nil {
|
if err := srv.runtime.graph.Delete(img.ID); err != nil {
|
||||||
return nil, fmt.Errorf("Cannot delete image %s: %s", name, err)
|
return nil, fmt.Errorf("Cannot delete image %s: %s", name, err)
|
||||||
|
@ -1608,6 +1618,20 @@ func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(img.ID, name) {
|
||||||
|
repository, tag = utils.ParseRepositoryTag(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we have a repo and the image is not referenced anywhere else
|
||||||
|
// then just perform an untag and do not validate.
|
||||||
|
//
|
||||||
|
// i.e. only validate if we are performing an actual delete and not
|
||||||
|
// an untag op
|
||||||
|
if repository != "" {
|
||||||
|
validate = len(srv.runtime.repositories.ByID()[img.ID]) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if validate {
|
||||||
// Prevent deletion if image is used by a container
|
// Prevent deletion if image is used by a container
|
||||||
for _, container := range srv.runtime.List() {
|
for _, container := range srv.runtime.List() {
|
||||||
parent, err := srv.runtime.repositories.LookupImage(container.Image)
|
parent, err := srv.runtime.repositories.LookupImage(container.Image)
|
||||||
|
@ -1624,13 +1648,8 @@ func (srv *Server) ImageDelete(name string, autoPrune bool) ([]APIRmi, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if strings.Contains(img.ID, name) {
|
|
||||||
//delete via ID
|
|
||||||
return srv.deleteImage(img, "", "")
|
|
||||||
}
|
}
|
||||||
name, tag := utils.ParseRepositoryTag(name)
|
return srv.deleteImage(img, repository, tag)
|
||||||
return srv.deleteImage(img, name, tag)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error) {
|
func (srv *Server) ImageGetCached(imgID string, config *Config) (*Image, error) {
|
||||||
|
|
Loading…
Reference in New Issue